diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d2aa1dd --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.sass-cache + +# cucumber +webrat.log + +# autogenerated stuff +site/js/jquery.ui.dial.js +site/css/style.css diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..88cec7f --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "vendor/turbosass"] + path = vendor/turbosass + url = git@github.com:thedjinn/turbosass.git +[submodule "vendor/jquery-ui-dial"] + path = vendor/jquery-ui-dial + url = git://github.com/thedjinn/jquery-ui-dial.git diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 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 +. diff --git a/Capfile b/Capfile new file mode 100644 index 0000000..d235f1d --- /dev/null +++ b/Capfile @@ -0,0 +1,95 @@ +load 'deploy' if respond_to?(:namespace) + +set :ssh_options, { :forward_agent => true } + +set :application, "js303" +set :user, "deploy" +set :use_sudo, false +set :stage, :production + +set :scm, :git +set :scm_verbose, true +set :git_enable_submodules, 1 +set :repository, "ssh://djinn@zooi.koffietijd.net:22223/home/djinn/git/js303" +set :branch, "master" +set :deploy_via, :remote_cache +set :deploy_to, "/home/#{user}/apps/#{application}" + +set :vps, "vps1.koffietijd.net" +role :app, vps +role :web, vps +role :db, vps, :primary => true + +set :runner, user +set :admin_runner, user + +set :current_path { fetch(:deploy_to) } +set(:latest_release) { fetch(:current_path) } +set(:release_path) { fetch(:current_path) } +set(:current_release) { fetch(:current_path) } + +set(:current_revision) { capture("cd #{current_path}; git rev-parse --short HEAD").strip } +set(:latest_revision) { capture("cd #{current_path}; git rev-parse --short HEAD").strip } +set(:previous_revision) { capture("cd #{current_path}; git rev-parse --short HEAD@{1}").strip } + +namespace :deploy do + task :default do + update + restart + end + + task :setup, :except => { :no_release => true } do + dirs = [deploy_to, shared_path] + dirs += shared_children.map { |d| File.join(shared_path, d) } + run "#{try_sudo} mkdir -p #{dirs.join(' ')} && #{try_sudo} chmod g+w #{dirs.join(' ')}" + run "git clone #{repository} #{current_path}" + end + + task :update do + transaction do + update_code + end + end + + desc "Update the deployed code." + task :update_code, :except => { :no_release => true } do + run "cd #{current_path}; git fetch origin; git reset --hard #{branch}" + #run "cd #{current_path}; rm public/stylesheets/*.css; rm -fr tmp/sass-cache" + finalize_update + end + + desc "Update the database (overwritten to avoid symlink)" + task :migrations do + update_code + #migrate + restart + end + + namespace :rollback do + desc "Moves the repo back to the previous version of HEAD" + task :repo, :except => { :no_release => true } do + set :branch, "HEAD@{1}" + deploy.default + end + + desc "Rewrite reflog so HEAD@{1} will continue to point to at the next previous release." + task :cleanup, :except => { :no_release => true } do + run "cd #{current_path}; git reflog delete --rewrite HEAD@{1}; git reflog delete --rewrite HEAD@{1}" + end + + desc "Rolls back to the previously deployed version." + task :default do + rollback.repo + rollback.cleanup + end + end + + [:start, :stop, :migrate].each do |t| + task t do ; end + end + + task :restart, :roles => :app, :except => { :no_release => true } do + # Restart Passenger + run "#{try_sudo} touch #{File.join(current_path, 'tmp', 'restart.txt')}" + end +end diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..d8e82d9 --- /dev/null +++ b/Gemfile @@ -0,0 +1,8 @@ +source "http://rubygems.org" + +gem "sinatra" +gem "sinatra-asset-pipeline" +gem "thin" +gem "slim" +gem "bower" +gem "pry" diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..acc7537 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,67 @@ +GEM + remote: http://rubygems.org/ + specs: + bower (0.0.2) + coderay (1.1.0) + coffee-script (2.3.0) + coffee-script-source + execjs + coffee-script-source (1.8.0) + daemons (1.1.9) + eventmachine (1.0.4) + execjs (2.2.2) + hike (1.2.3) + method_source (0.8.2) + multi_json (1.10.1) + pry (0.10.1) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) + rack (1.6.0) + rack-protection (1.5.3) + rack + rake (10.4.2) + sass (3.4.9) + sinatra (1.4.5) + rack (~> 1.4) + rack-protection (~> 1.4) + tilt (~> 1.3, >= 1.3.4) + sinatra-asset-pipeline (0.6.0) + coffee-script (~> 2.3) + rake (~> 10.0) + sass (~> 3.1) + sinatra (~> 1.4) + sprockets (~> 2.12) + sprockets-helpers (~> 1.1) + sprockets-sass (~> 1.2) + slim (3.0.1) + temple (~> 0.7.3) + tilt (>= 1.3.3, < 2.1) + slop (3.6.0) + sprockets (2.12.3) + hike (~> 1.2) + multi_json (~> 1.0) + rack (~> 1.0) + tilt (~> 1.1, != 1.3.0) + sprockets-helpers (1.1.0) + sprockets (~> 2.0) + sprockets-sass (1.3.1) + sprockets (~> 2.0) + tilt (~> 1.1) + temple (0.7.5) + thin (1.6.3) + daemons (~> 1.0, >= 1.0.9) + eventmachine (~> 1.0) + rack (~> 1.0) + tilt (1.4.1) + +PLATFORMS + ruby + +DEPENDENCIES + bower + pry + sinatra + sinatra-asset-pipeline + slim + thin diff --git a/README.md b/README.md new file mode 100644 index 0000000..0b3acf6 --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +# JS303 - A TB-303 clone in JavaScript + +## What's this? + +You are looking at the source code for JS303, a fully functional TB-303 clone +written in JavaScript using the Web Audio API. It was written for the second +GrunnJS meetup which was held in November 2014. + +The accompanying presentation for this project can be found at: + +https://www.youtube.com/watch?v=YyVsKlKoNbA#t=2938 + +## How to use it? + +First, make sure you have a recent Ruby installed and also Node.js and +CoffeeScript. + +Then, clone the repository, run `bundle install`, and then `thin start`. Now +go to `localhost:3000` and rock it! + +## License + +First of all, if you use this software and make a hit song, buy me some +coffee! + +Copyright (C) 2014 Emil Loer + +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/. diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..756d6d3 --- /dev/null +++ b/Rakefile @@ -0,0 +1,12 @@ +ROOT = File.dirname(__FILE__) + +task :default do + chdir ROOT + sh "sass --scss src/style.scss site/css/style.css" + cp "vendor/jquery-ui-dial/jquery.ui.dial.js", "site/js/jquery.ui.dial.js" +end + +task :sass do + chdir ROOT + sh "sass --scss --watch src/style.scss:site/css/style.css" +end diff --git a/app.rb b/app.rb new file mode 100644 index 0000000..b89f176 --- /dev/null +++ b/app.rb @@ -0,0 +1,14 @@ +Bundler.require + +# Enable asset pipeline +require 'sinatra/asset_pipeline' +register Sinatra::AssetPipeline + +# Add support for bower components +configure do + settings.sprockets.append_path "./bower_components" +end + +get "/" do + slim :index +end diff --git a/assets/javascripts/app.js.coffee b/assets/javascripts/app.js.coffee new file mode 100644 index 0000000..7e78834 --- /dev/null +++ b/assets/javascripts/app.js.coffee @@ -0,0 +1,256 @@ +#= require jquery/dist/jquery +#= require handlebars/handlebars +#= require emblem/dist/emblem +#= require ember/ember +#= require jquery-knob/dist/jquery.knob.min +#= require synth + +lin2exp = (x, inMin, inMax, outMin, outMax) -> + tmp = (x - inMin) / (inMax - inMin) + outMin * Math.exp(tmp * Math.log(outMax / outMin)) + +lin2lin = (x, inMin, inMax, outMin, outMax) -> + tmp = (x - inMin) / (inMax - inMin) + outMin + tmp * (outMax - outMin) + +randomBool = -> !!Math.round(Math.random()) + +Ember.Handlebars.registerHelper "group", (options) -> + data = options.data + fn = options.fn + view = data.view + + childView = view.createChildView Ember._MetamorphView, + context: Ember.get(view, "context") + + template: (context, options) -> + options.data.insideGroup = true + return fn(context, options) + + view.appendChild childView + +Step = Ember.Object.extend + pitch: 50 + gate: true + slide: false + accent: false + up: false + down: false + + randomize: -> + @set "pitch", 40 + [0, 2, 3, 5, 7, 8, 10, 12][Math.round(7 * Math.random())] + @set "gate", randomBool() + @set "slide", randomBool() + @set "accent", randomBool() + @set "up", randomBool() + @set "down", randomBool() + + clear: -> + @set "pitch", 50 + @set "gate", true + @set "slide", false + @set "accent", false + @set "up", false + @set "down", false + +Pattern = Ember.Object.extend + numberOfSteps: 16 + + init: -> + @set "steps", (new Step for _ in [0..15]) + + randomize: -> + step.randomize() for step in @get("steps") + + clear: -> + step.clear() for step in @get("steps") + +window.App = App = Ember.Application.create() + +App.KnobView = Ember.View.extend + tagName: "input" + + min: 0 + max: 1 + value: 0.5 + step: 0.01 + + initKnob: (-> + @$().knob + fgColor: "#fc3932" + bgColor: "#cccccc" + inputColor: "#000000" + font: "Abel" + fontWeight: "normal" + min: Number(@get("min")) + max: Number(@get("max")) + step: Number(@get("step")) + width: 106 + height: 85 + angleOffset: -125 + angleArc: 250 + change: (value) => + @set "value", value + + @$().val(@get("value")).trigger("change") + ).on('didInsertElement') + + valueChanged: (-> + @$().val(@get("value")).trigger("change") + @trigger "change" + ).observes("value") + +App.ToggleButtonView = Ember.View.extend + tagName: "button" + classNames: ["toggle-button"] + classNameBindings: ["active:on"] + templateName: "toggle_button" + + active: true + title: "" + + mouseDown: -> + @set "active", !@get("active") + +App.ButtonView = Ember.View.extend Ember.TargetActionSupport, + tagName: "button" + classNames: ["button"] + templateName: "button" + + title: "" + + click: -> + @triggerAction + action: @get("action") + target: @get("target") + +App.SelectorButtonView = App.ButtonView.extend + classNameBindings: ["isSelected::grey"] + + isSelected: (-> + @get("value") == @get("variable") + ).property("value", "variable") + + click: -> @set "variable", @get("value") + +App.PitchButtonView = App.SelectorButtonView.extend + templateName: null + mouseDown: -> @set "variable", @get("value") + click: null + +App.ApplicationController = Ember.ObjectController.extend + patterns: (new Pattern for _ in [0..7]) + allowedPitches: [52..40] + + tempo: 120 + cutoff: 0.5 + resonance: 0.5 + envmod: 0.0 + decay: 0.2 + accent: 0.5 + distortion: 0.0 + foldback: 0.0 + delaySteps: 3 + delayMix: 0 + delayFeedback: 0.5 + waveform: 0 + + cutoffChanged: (-> + @synth.setcutoff lin2exp(@get("cutoff"), 0, 1, 20, 20000) + ).observes("cutoff").on("init") + + resonanceChanged: (-> + @synth.setresonance @get("resonance") + ).observes("resonance").on("init") + + envmodChanged: (-> + @synth.setenvmod @get("envmod") + ).observes("envmod").on("init") + + decayChanged: (-> + @synth.decay = lin2lin(@get("decay"), 0, 1, 20, 4000) + ).observes("decay").on("init") + + accentChanged: (-> + @synth.accent = @get("accent") + ).observes("accent").on("init") + + tempoChanged: (-> + @synth.settempo @get("tempo") + ).observes("tempo").on("init") + + waveformChanged: (-> + @synth.waveform = @get("waveform") == 1 + ).observes("waveform").on("init") + + distortionChanged: (-> + @synth.setdistthreshold @get("distortion") + ).observes("distortion").on("init") + + foldbackChanged: (-> + @synth.dist_shape = @get("foldback") + ).observes("foldback").on("init") + + delayStepsChanged: (-> + @synth.delay_length = @synth.steplength * Math.round(@get("delaySteps")) + ).observes("delaySteps", "tempo").on("init") + + delayMixChanged: (-> + @synth.delay_send = @get("delayMix") + ).observes("delayMix").on("init") + + delayFeedbackChanged: (-> + @synth.delay_feedback = @get("delayFeedback") + ).observes("delayFeedback").on("init") + + columns: (-> + @get("currentPattern").get("steps").map (step, index) -> + step: step + index: index + 1 + highlight: index % 4 == 0 + ).property("currentPattern.steps.@each") + + init: -> + @_super.apply this, arguments + + @synth = new TB303 genwavetable() + + @synth.waveform = 1 + + @synth.onStepChanged = => @stepChanged() + + @set "audioManager", new AudioManager(@synth) + @set "currentPattern", @patterns[0] + + stepChanged: -> + $(".playing").removeClass("playing") + $(".step-column").eq(@synth.pos + 1).addClass("playing") + + currentPatternChanged: (-> + @synth.pattern ||= @get("currentPattern") + @synth.nextPattern = @get("currentPattern") + ).observes("currentPattern").on("init") + +class AudioManager + constructor: (@synth) -> + @context = new AudioContext + + @bufferSize = 4096 + + @processor = @context.createScriptProcessor @bufferSize, 0, 1 + @processor.onaudioprocess = @audioCallback + @processor.connect @context.destination + + audioCallback: (e) => + output = e.outputBuffer.getChannelData 0 + + for i in [0..@bufferSize] by 1 + output[i] = @synth.render() + + start: -> + @synth.reset() + @synth.running = true + + stop: -> + @synth.running = false + $(".playing").removeClass("playing") diff --git a/assets/javascripts/htmlbars/htmlbars-compiler.amd.js b/assets/javascripts/htmlbars/htmlbars-compiler.amd.js new file mode 100644 index 0000000..bcb0174 --- /dev/null +++ b/assets/javascripts/htmlbars/htmlbars-compiler.amd.js @@ -0,0 +1,7953 @@ +define("handlebars/base", + ["./utils","./exception","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Utils = __dependency1__; + var Exception = __dependency2__["default"]; + + var VERSION = "1.3.0"; + __exports__.VERSION = VERSION;var COMPILER_REVISION = 4; + __exports__.COMPILER_REVISION = COMPILER_REVISION; + var REVISION_CHANGES = { + 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it + 2: '== 1.0.0-rc.3', + 3: '== 1.0.0-rc.4', + 4: '>= 1.0.0' + }; + __exports__.REVISION_CHANGES = REVISION_CHANGES; + var isArray = Utils.isArray, + isFunction = Utils.isFunction, + toString = Utils.toString, + objectType = '[object Object]'; + + function HandlebarsEnvironment(helpers, partials) { + this.helpers = helpers || {}; + this.partials = partials || {}; + + registerDefaultHelpers(this); + } + + __exports__.HandlebarsEnvironment = HandlebarsEnvironment;HandlebarsEnvironment.prototype = { + constructor: HandlebarsEnvironment, + + logger: logger, + log: log, + + registerHelper: function(name, fn, inverse) { + if (toString.call(name) === objectType) { + if (inverse || fn) { throw new Exception('Arg not supported with multiple helpers'); } + Utils.extend(this.helpers, name); + } else { + if (inverse) { fn.not = inverse; } + this.helpers[name] = fn; + } + }, + + registerPartial: function(name, str) { + if (toString.call(name) === objectType) { + Utils.extend(this.partials, name); + } else { + this.partials[name] = str; + } + } + }; + + function registerDefaultHelpers(instance) { + instance.registerHelper('helperMissing', function(arg) { + if(arguments.length === 2) { + return undefined; + } else { + throw new Exception("Missing helper: '" + arg + "'"); + } + }); + + instance.registerHelper('blockHelperMissing', function(context, options) { + var inverse = options.inverse || function() {}, fn = options.fn; + + if (isFunction(context)) { context = context.call(this); } + + if(context === true) { + return fn(this); + } else if(context === false || context == null) { + return inverse(this); + } else if (isArray(context)) { + if(context.length > 0) { + return instance.helpers.each(context, options); + } else { + return inverse(this); + } + } else { + return fn(context); + } + }); + + instance.registerHelper('each', function(context, options) { + var fn = options.fn, inverse = options.inverse; + var i = 0, ret = "", data; + + if (isFunction(context)) { context = context.call(this); } + + if (options.data) { + data = createFrame(options.data); + } + + if(context && typeof context === 'object') { + if (isArray(context)) { + for(var j = context.length; i 0) { + throw new Exception("Invalid path: " + original, this); + } else if (part === "..") { + depth++; + } else { + this.isScoped = true; + } + } else { + dig.push(part); + } + } + + this.original = original; + this.parts = dig; + this.string = dig.join('.'); + this.depth = depth; + + // an ID is simple if it only has one part, and that part is not + // `..` or `this`. + this.isSimple = parts.length === 1 && !this.isScoped && depth === 0; + + this.stringModeValue = this.string; + }, + + PartialNameNode: function(name, locInfo) { + LocationInfo.call(this, locInfo); + this.type = "PARTIAL_NAME"; + this.name = name.original; + }, + + DataNode: function(id, locInfo) { + LocationInfo.call(this, locInfo); + this.type = "DATA"; + this.id = id; + }, + + StringNode: function(string, locInfo) { + LocationInfo.call(this, locInfo); + this.type = "STRING"; + this.original = + this.string = + this.stringModeValue = string; + }, + + IntegerNode: function(integer, locInfo) { + LocationInfo.call(this, locInfo); + this.type = "INTEGER"; + this.original = + this.integer = integer; + this.stringModeValue = Number(integer); + }, + + BooleanNode: function(bool, locInfo) { + LocationInfo.call(this, locInfo); + this.type = "BOOLEAN"; + this.bool = bool; + this.stringModeValue = bool === "true"; + }, + + CommentNode: function(comment, locInfo) { + LocationInfo.call(this, locInfo); + this.type = "comment"; + this.comment = comment; + } + }; + + // Must be exported as an object rather than the root of the module as the jison lexer + // most modify the object to operate properly. + __exports__["default"] = AST; + }); +define("handlebars/compiler/base", + ["./parser","./ast","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var parser = __dependency1__["default"]; + var AST = __dependency2__["default"]; + + __exports__.parser = parser; + + function parse(input) { + // Just return if an already-compile AST was passed in. + if(input.constructor === AST.ProgramNode) { return input; } + + parser.yy = AST; + return parser.parse(input); + } + + __exports__.parse = parse; + }); +define("handlebars/compiler/compiler", + ["../exception","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Exception = __dependency1__["default"]; + + function Compiler() {} + + __exports__.Compiler = Compiler;// the foundHelper register will disambiguate helper lookup from finding a + // function in a context. This is necessary for mustache compatibility, which + // requires that context functions in blocks are evaluated by blockHelperMissing, + // and then proceed as if the resulting value was provided to blockHelperMissing. + + Compiler.prototype = { + compiler: Compiler, + + disassemble: function() { + var opcodes = this.opcodes, opcode, out = [], params, param; + + for (var i=0, l=opcodes.length; i 0) { + this.source[1] = this.source[1] + ", " + locals.join(", "); + } + + // Generate minimizer alias mappings + if (!this.isChild) { + for (var alias in this.context.aliases) { + if (this.context.aliases.hasOwnProperty(alias)) { + this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias]; + } + } + } + + if (this.source[1]) { + this.source[1] = "var " + this.source[1].substring(2) + ";"; + } + + // Merge children + if (!this.isChild) { + this.source[1] += '\n' + this.context.programs.join('\n') + '\n'; + } + + if (!this.environment.isSimple) { + this.pushSource("return buffer;"); + } + + var params = this.isChild ? ["depth0", "data"] : ["Handlebars", "depth0", "helpers", "partials", "data"]; + + for(var i=0, l=this.environment.depths.list.length; i this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); } + return this.topStackName(); + }, + topStackName: function() { + return "stack" + this.stackSlot; + }, + flushInline: function() { + var inlineStack = this.inlineStack; + if (inlineStack.length) { + this.inlineStack = []; + for (var i = 0, len = inlineStack.length; i < len; i++) { + var entry = inlineStack[i]; + if (entry instanceof Literal) { + this.compileStack.push(entry); + } else { + this.pushStack(entry); + } + } + } + }, + isInline: function() { + return this.inlineStack.length; + }, + + popStack: function(wrapped) { + var inline = this.isInline(), + item = (inline ? this.inlineStack : this.compileStack).pop(); + + if (!wrapped && (item instanceof Literal)) { + return item.value; + } else { + if (!inline) { + if (!this.stackSlot) { + throw new Exception('Invalid stack pop'); + } + this.stackSlot--; + } + return item; + } + }, + + topStack: function(wrapped) { + var stack = (this.isInline() ? this.inlineStack : this.compileStack), + item = stack[stack.length - 1]; + + if (!wrapped && (item instanceof Literal)) { + return item.value; + } else { + return item; + } + }, + + quotedString: function(str) { + return '"' + str + .replace(/\\/g, '\\\\') + .replace(/"/g, '\\"') + .replace(/\n/g, '\\n') + .replace(/\r/g, '\\r') + .replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4 + .replace(/\u2029/g, '\\u2029') + '"'; + }, + + setupHelper: function(paramSize, name, missingParams) { + var params = [], + paramsInit = this.setupParams(paramSize, params, missingParams); + var foundHelper = this.nameLookup('helpers', name, 'helper'); + + return { + params: params, + paramsInit: paramsInit, + name: foundHelper, + callParams: ["depth0"].concat(params).join(", "), + helperMissingParams: missingParams && ["depth0", this.quotedString(name)].concat(params).join(", ") + }; + }, + + setupOptions: function(paramSize, params) { + var options = [], contexts = [], types = [], param, inverse, program; + + options.push("hash:" + this.popStack()); + + if (this.options.stringParams) { + options.push("hashTypes:" + this.popStack()); + options.push("hashContexts:" + this.popStack()); + } + + inverse = this.popStack(); + program = this.popStack(); + + // Avoid setting fn and inverse if neither are set. This allows + // helpers to do a check for `if (options.fn)` + if (program || inverse) { + if (!program) { + this.context.aliases.self = "this"; + program = "self.noop"; + } + + if (!inverse) { + this.context.aliases.self = "this"; + inverse = "self.noop"; + } + + options.push("inverse:" + inverse); + options.push("fn:" + program); + } + + for(var i=0; i 2) { + expected.push("'" + this.terminals_[p] + "'"); + } + if (this.lexer.showPosition) { + errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'"; + } else { + errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1?"end of input":"'" + (this.terminals_[symbol] || symbol) + "'"); + } + this.parseError(errStr, {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected}); + } + } + if (action[0] instanceof Array && action.length > 1) { + throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol); + } + switch (action[0]) { + case 1: + stack.push(symbol); + vstack.push(this.lexer.yytext); + lstack.push(this.lexer.yylloc); + stack.push(action[1]); + symbol = null; + if (!preErrorSymbol) { + yyleng = this.lexer.yyleng; + yytext = this.lexer.yytext; + yylineno = this.lexer.yylineno; + yyloc = this.lexer.yylloc; + if (recovering > 0) + recovering--; + } else { + symbol = preErrorSymbol; + preErrorSymbol = null; + } + break; + case 2: + len = this.productions_[action[1]][1]; + yyval.$ = vstack[vstack.length - len]; + yyval._$ = {first_line: lstack[lstack.length - (len || 1)].first_line, last_line: lstack[lstack.length - 1].last_line, first_column: lstack[lstack.length - (len || 1)].first_column, last_column: lstack[lstack.length - 1].last_column}; + if (ranges) { + yyval._$.range = [lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1]]; + } + r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack); + if (typeof r !== "undefined") { + return r; + } + if (len) { + stack = stack.slice(0, -1 * len * 2); + vstack = vstack.slice(0, -1 * len); + lstack = lstack.slice(0, -1 * len); + } + stack.push(this.productions_[action[1]][0]); + vstack.push(yyval.$); + lstack.push(yyval._$); + newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; + stack.push(newState); + break; + case 3: + return true; + } + } + return true; + } + }; + + + function stripFlags(open, close) { + return { + left: open.charAt(2) === '~', + right: close.charAt(0) === '~' || close.charAt(1) === '~' + }; + } + + /* Jison generated lexer */ + var lexer = (function(){ + var lexer = ({EOF:1, + parseError:function parseError(str, hash) { + if (this.yy.parser) { + this.yy.parser.parseError(str, hash); + } else { + throw new Error(str); + } + }, + setInput:function (input) { + this._input = input; + this._more = this._less = this.done = false; + this.yylineno = this.yyleng = 0; + this.yytext = this.matched = this.match = ''; + this.conditionStack = ['INITIAL']; + this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0}; + if (this.options.ranges) this.yylloc.range = [0,0]; + this.offset = 0; + return this; + }, + input:function () { + var ch = this._input[0]; + this.yytext += ch; + this.yyleng++; + this.offset++; + this.match += ch; + this.matched += ch; + var lines = ch.match(/(?:\r\n?|\n).*/g); + if (lines) { + this.yylineno++; + this.yylloc.last_line++; + } else { + this.yylloc.last_column++; + } + if (this.options.ranges) this.yylloc.range[1]++; + + this._input = this._input.slice(1); + return ch; + }, + unput:function (ch) { + var len = ch.length; + var lines = ch.split(/(?:\r\n?|\n)/g); + + this._input = ch + this._input; + this.yytext = this.yytext.substr(0, this.yytext.length-len-1); + //this.yyleng -= len; + this.offset -= len; + var oldLines = this.match.split(/(?:\r\n?|\n)/g); + this.match = this.match.substr(0, this.match.length-1); + this.matched = this.matched.substr(0, this.matched.length-1); + + if (lines.length-1) this.yylineno -= lines.length-1; + var r = this.yylloc.range; + + this.yylloc = {first_line: this.yylloc.first_line, + last_line: this.yylineno+1, + first_column: this.yylloc.first_column, + last_column: lines ? + (lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length: + this.yylloc.first_column - len + }; + + if (this.options.ranges) { + this.yylloc.range = [r[0], r[0] + this.yyleng - len]; + } + return this; + }, + more:function () { + this._more = true; + return this; + }, + less:function (n) { + this.unput(this.match.slice(n)); + }, + pastInput:function () { + var past = this.matched.substr(0, this.matched.length - this.match.length); + return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, ""); + }, + upcomingInput:function () { + var next = this.match; + if (next.length < 20) { + next += this._input.substr(0, 20-next.length); + } + return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, ""); + }, + showPosition:function () { + var pre = this.pastInput(); + var c = new Array(pre.length + 1).join("-"); + return pre + this.upcomingInput() + "\n" + c+"^"; + }, + next:function () { + if (this.done) { + return this.EOF; + } + if (!this._input) this.done = true; + + var token, + match, + tempMatch, + index, + col, + lines; + if (!this._more) { + this.yytext = ''; + this.match = ''; + } + var rules = this._currentRules(); + for (var i=0;i < rules.length; i++) { + tempMatch = this._input.match(this.rules[rules[i]]); + if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { + match = tempMatch; + index = i; + if (!this.options.flex) break; + } + } + if (match) { + lines = match[0].match(/(?:\r\n?|\n).*/g); + if (lines) this.yylineno += lines.length; + this.yylloc = {first_line: this.yylloc.last_line, + last_line: this.yylineno+1, + first_column: this.yylloc.last_column, + last_column: lines ? lines[lines.length-1].length-lines[lines.length-1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length}; + this.yytext += match[0]; + this.match += match[0]; + this.matches = match; + this.yyleng = this.yytext.length; + if (this.options.ranges) { + this.yylloc.range = [this.offset, this.offset += this.yyleng]; + } + this._more = false; + this._input = this._input.slice(match[0].length); + this.matched += match[0]; + token = this.performAction.call(this, this.yy, this, rules[index],this.conditionStack[this.conditionStack.length-1]); + if (this.done && this._input) this.done = false; + if (token) return token; + else return; + } + if (this._input === "") { + return this.EOF; + } else { + return this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(), + {text: "", token: null, line: this.yylineno}); + } + }, + lex:function lex() { + var r = this.next(); + if (typeof r !== 'undefined') { + return r; + } else { + return this.lex(); + } + }, + begin:function begin(condition) { + this.conditionStack.push(condition); + }, + popState:function popState() { + return this.conditionStack.pop(); + }, + _currentRules:function _currentRules() { + return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules; + }, + topState:function () { + return this.conditionStack[this.conditionStack.length-2]; + }, + pushState:function begin(condition) { + this.begin(condition); + }}); + lexer.options = {}; + lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) { + + + function strip(start, end) { + return yy_.yytext = yy_.yytext.substr(start, yy_.yyleng-end); + } + + + var YYSTATE=YY_START + switch($avoiding_name_collisions) { + case 0: + if(yy_.yytext.slice(-2) === "\\\\") { + strip(0,1); + this.begin("mu"); + } else if(yy_.yytext.slice(-1) === "\\") { + strip(0,1); + this.begin("emu"); + } else { + this.begin("mu"); + } + if(yy_.yytext) return 14; + + break; + case 1:return 14; + break; + case 2: + this.popState(); + return 14; + + break; + case 3:strip(0,4); this.popState(); return 15; + break; + case 4:return 35; + break; + case 5:return 36; + break; + case 6:return 25; + break; + case 7:return 16; + break; + case 8:return 20; + break; + case 9:return 19; + break; + case 10:return 19; + break; + case 11:return 23; + break; + case 12:return 22; + break; + case 13:this.popState(); this.begin('com'); + break; + case 14:strip(3,5); this.popState(); return 15; + break; + case 15:return 22; + break; + case 16:return 41; + break; + case 17:return 40; + break; + case 18:return 40; + break; + case 19:return 44; + break; + case 20:// ignore whitespace + break; + case 21:this.popState(); return 24; + break; + case 22:this.popState(); return 18; + break; + case 23:yy_.yytext = strip(1,2).replace(/\\"/g,'"'); return 32; + break; + case 24:yy_.yytext = strip(1,2).replace(/\\'/g,"'"); return 32; + break; + case 25:return 42; + break; + case 26:return 34; + break; + case 27:return 34; + break; + case 28:return 33; + break; + case 29:return 40; + break; + case 30:yy_.yytext = strip(1,2); return 40; + break; + case 31:return 'INVALID'; + break; + case 32:return 5; + break; + } + }; + lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\()/,/^(?:\))/,/^(?:\{\{(~)?>)/,/^(?:\{\{(~)?#)/,/^(?:\{\{(~)?\/)/,/^(?:\{\{(~)?\^)/,/^(?:\{\{(~)?\s*else\b)/,/^(?:\{\{(~)?\{)/,/^(?:\{\{(~)?&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{(~)?)/,/^(?:=)/,/^(?:\.\.)/,/^(?:\.(?=([=~}\s\/.)])))/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}(~)?\}\})/,/^(?:(~)?\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@)/,/^(?:true(?=([~}\s)])))/,/^(?:false(?=([~}\s)])))/,/^(?:-?[0-9]+(?=([~}\s)])))/,/^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)]))))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:$)/]; + lexer.conditions = {"mu":{"rules":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"com":{"rules":[3],"inclusive":false},"INITIAL":{"rules":[0,1,32],"inclusive":true}}; + return lexer;})() + parser.lexer = lexer; + function Parser () { this.yy = {}; }Parser.prototype = parser;parser.Parser = Parser; + return new Parser; + })();__exports__["default"] = handlebars; + /* jshint ignore:end */ + }); +define("handlebars/compiler/printer", + ["./visitor","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Visitor = __dependency1__["default"]; + + function print(ast) { + return new PrintVisitor().accept(ast); + } + + __exports__.print = print;function PrintVisitor() { + this.padding = 0; + } + + __exports__.PrintVisitor = PrintVisitor;PrintVisitor.prototype = new Visitor(); + + PrintVisitor.prototype.pad = function(string, newline) { + var out = ""; + + for(var i=0,l=this.padding; i " + content + " }}"); + }; + + PrintVisitor.prototype.hash = function(hash) { + var pairs = hash.pairs; + var joinedPairs = [], left, right; + + for(var i=0, l=pairs.length; i 1) { + return "PATH:" + path; + } else { + return "ID:" + path; + } + }; + + PrintVisitor.prototype.PARTIAL_NAME = function(partialName) { + return "PARTIAL:" + partialName.name; + }; + + PrintVisitor.prototype.DATA = function(data) { + return "@" + this.accept(data.id); + }; + + PrintVisitor.prototype.content = function(content) { + return this.pad("CONTENT[ '" + content.string + "' ]"); + }; + + PrintVisitor.prototype.comment = function(comment) { + return this.pad("{{! '" + comment.comment + "' }}"); + }; + }); +define("handlebars/compiler/visitor", + ["exports"], + function(__exports__) { + "use strict"; + function Visitor() {} + + Visitor.prototype = { + constructor: Visitor, + + accept: function(object) { + return this[object.type](object); + } + }; + + __exports__["default"] = Visitor; + }); +define("handlebars/exception", + ["exports"], + function(__exports__) { + "use strict"; + + var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; + + function Exception(message, node) { + var line; + if (node && node.firstLine) { + line = node.firstLine; + + message += ' - ' + line + ':' + node.firstColumn; + } + + var tmp = Error.prototype.constructor.call(this, message); + + // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. + for (var idx = 0; idx < errorProps.length; idx++) { + this[errorProps[idx]] = tmp[errorProps[idx]]; + } + + if (line) { + this.lineNumber = line; + this.column = node.firstColumn; + } + } + + Exception.prototype = new Error(); + + __exports__["default"] = Exception; + }); +define("handlebars/runtime", + ["./utils","./exception","./base","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Utils = __dependency1__; + var Exception = __dependency2__["default"]; + var COMPILER_REVISION = __dependency3__.COMPILER_REVISION; + var REVISION_CHANGES = __dependency3__.REVISION_CHANGES; + + function checkRevision(compilerInfo) { + var compilerRevision = compilerInfo && compilerInfo[0] || 1, + currentRevision = COMPILER_REVISION; + + if (compilerRevision !== currentRevision) { + if (compilerRevision < currentRevision) { + var runtimeVersions = REVISION_CHANGES[currentRevision], + compilerVersions = REVISION_CHANGES[compilerRevision]; + throw new Exception("Template was precompiled with an older version of Handlebars than the current runtime. "+ + "Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+")."); + } else { + // Use the embedded version info since the runtime doesn't know about this revision yet + throw new Exception("Template was precompiled with a newer version of Handlebars than the current runtime. "+ + "Please update your runtime to a newer version ("+compilerInfo[1]+")."); + } + } + } + + __exports__.checkRevision = checkRevision;// TODO: Remove this line and break up compilePartial + + function template(templateSpec, env) { + if (!env) { + throw new Exception("No environment passed to template"); + } + + // Note: Using env.VM references rather than local var references throughout this section to allow + // for external users to override these as psuedo-supported APIs. + var invokePartialWrapper = function(partial, name, context, helpers, partials, data) { + var result = env.VM.invokePartial.apply(this, arguments); + if (result != null) { return result; } + + if (env.compile) { + var options = { helpers: helpers, partials: partials, data: data }; + partials[name] = env.compile(partial, { data: data !== undefined }, env); + return partials[name](context, options); + } else { + throw new Exception("The partial " + name + " could not be compiled when running in runtime-only mode"); + } + }; + + // Just add water + var container = { + escapeExpression: Utils.escapeExpression, + invokePartial: invokePartialWrapper, + programs: [], + program: function(i, fn, data) { + var programWrapper = this.programs[i]; + if(data) { + programWrapper = program(i, fn, data); + } else if (!programWrapper) { + programWrapper = this.programs[i] = program(i, fn); + } + return programWrapper; + }, + merge: function(param, common) { + var ret = param || common; + + if (param && common && (param !== common)) { + ret = {}; + Utils.extend(ret, common); + Utils.extend(ret, param); + } + return ret; + }, + programWithDepth: env.VM.programWithDepth, + noop: env.VM.noop, + compilerInfo: null + }; + + return function(context, options) { + options = options || {}; + var namespace = options.partial ? options : env, + helpers, + partials; + + if (!options.partial) { + helpers = options.helpers; + partials = options.partials; + } + var result = templateSpec.call( + container, + namespace, context, + helpers, + partials, + options.data); + + if (!options.partial) { + env.VM.checkRevision(container.compilerInfo); + } + + return result; + }; + } + + __exports__.template = template;function programWithDepth(i, fn, data /*, $depth */) { + var args = Array.prototype.slice.call(arguments, 3); + + var prog = function(context, options) { + options = options || {}; + + return fn.apply(this, [context, options.data || data].concat(args)); + }; + prog.program = i; + prog.depth = args.length; + return prog; + } + + __exports__.programWithDepth = programWithDepth;function program(i, fn, data) { + var prog = function(context, options) { + options = options || {}; + + return fn(context, options.data || data); + }; + prog.program = i; + prog.depth = 0; + return prog; + } + + __exports__.program = program;function invokePartial(partial, name, context, helpers, partials, data) { + var options = { partial: true, helpers: helpers, partials: partials, data: data }; + + if(partial === undefined) { + throw new Exception("The partial " + name + " could not be found"); + } else if(partial instanceof Function) { + return partial(context, options); + } + } + + __exports__.invokePartial = invokePartial;function noop() { return ""; } + + __exports__.noop = noop; + }); +define("handlebars/safe-string", + ["exports"], + function(__exports__) { + "use strict"; + // Build out our basic SafeString type + function SafeString(string) { + this.string = string; + } + + SafeString.prototype.toString = function() { + return "" + this.string; + }; + + __exports__["default"] = SafeString; + }); +define("handlebars/utils", + ["./safe-string","exports"], + function(__dependency1__, __exports__) { + "use strict"; + /*jshint -W004 */ + var SafeString = __dependency1__["default"]; + + var escape = { + "&": "&", + "<": "<", + ">": ">", + '"': """, + "'": "'", + "`": "`" + }; + + var badChars = /[&<>"'`]/g; + var possible = /[&<>"'`]/; + + function escapeChar(chr) { + return escape[chr] || "&"; + } + + function extend(obj, value) { + for(var key in value) { + if(Object.prototype.hasOwnProperty.call(value, key)) { + obj[key] = value[key]; + } + } + } + + __exports__.extend = extend;var toString = Object.prototype.toString; + __exports__.toString = toString; + // Sourced from lodash + // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt + var isFunction = function(value) { + return typeof value === 'function'; + }; + // fallback for older versions of Chrome and Safari + if (isFunction(/x/)) { + isFunction = function(value) { + return typeof value === 'function' && toString.call(value) === '[object Function]'; + }; + } + var isFunction; + __exports__.isFunction = isFunction; + var isArray = Array.isArray || function(value) { + return (value && typeof value === 'object') ? toString.call(value) === '[object Array]' : false; + }; + __exports__.isArray = isArray; + + function escapeExpression(string) { + // don't escape SafeStrings, since they're already safe + if (string instanceof SafeString) { + return string.toString(); + } else if (!string && string !== 0) { + return ""; + } + + // Force a string conversion as this will be done by the append regardless and + // the regex test will do this transparently behind the scenes, causing issues if + // an object's to string has escaped characters in it. + string = "" + string; + + if(!possible.test(string)) { return string; } + return string.replace(badChars, escapeChar); + } + + __exports__.escapeExpression = escapeExpression;function isEmpty(value) { + if (!value && value !== 0) { + return true; + } else if (isArray(value) && value.length === 0) { + return true; + } else { + return false; + } + } + + __exports__.isEmpty = isEmpty; + }); +define("htmlbars-compiler", + ["./htmlbars-compiler/compiler","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var compilerSpec = __dependency1__.compilerSpec; + var compilerSpec; + __exports__.compilerSpec = compilerSpec; + }); +define("htmlbars-compiler/ast", + ["../handlebars/compiler/ast","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var AST = __dependency1__["default"]; + + var MustacheNode = AST.MustacheNode; + __exports__.MustacheNode = MustacheNode;var SexprNode = AST.SexprNode; + __exports__.SexprNode = SexprNode;var HashNode = AST.HashNode; + __exports__.HashNode = HashNode;var IdNode = AST.IdNode; + __exports__.IdNode = IdNode;var StringNode = AST.StringNode; + __exports__.StringNode = StringNode; + function ProgramNode(statements, strip) { + this.type = 'program'; + this.statements = statements; + this.strip = strip; + } + + __exports__.ProgramNode = ProgramNode;function BlockNode(mustache, program, inverse, strip) { + this.type = 'block'; + this.mustache = mustache; + this.program = program; + this.inverse = inverse; + this.strip = strip; + } + + __exports__.BlockNode = BlockNode;function ComponentNode(tag, attributes, program) { + this.type = 'component'; + this.tag = tag; + this.attributes = attributes; + this.program = program; + } + + __exports__.ComponentNode = ComponentNode;function ElementNode(tag, attributes, helpers, children) { + this.type = 'element'; + this.tag = tag; + this.attributes = attributes; + this.helpers = helpers; + this.children = children; + } + + __exports__.ElementNode = ElementNode;function PartialNode(name) { + this.id = {}; + this.id.string = this.name = 'partial'; + this.type = 'mustache'; + this.params = [name]; + this.program = null; + this.inverse = null; + this.hash = undefined; + this.escaped = true; + this.isHelper = true; + } + + __exports__.PartialNode = PartialNode;function AttrNode(name, value) { + this.type = 'attr'; + this.name = name; + this.value = value; + } + + __exports__.AttrNode = AttrNode;function TextNode(chars) { + this.type = 'text'; + this.chars = chars; + } + + __exports__.TextNode = TextNode;function childrenFor(node) { + if (node.type === 'program') return node.statements; + if (node.type === 'element') return node.children; + } + + __exports__.childrenFor = childrenFor;function usesMorph(node) { + return node.type === 'mustache' || node.type === 'block' || node.type === 'component'; + } + + __exports__.usesMorph = usesMorph;function appendChild(parent, node) { + var children = childrenFor(parent); + + var len = children.length, last; + if (len > 0) { + last = children[len-1]; + if (usesMorph(last) && usesMorph(node)) { + children.push(new TextNode('')); + } + } + children.push(node); + } + + __exports__.appendChild = appendChild; + }); +define("htmlbars-compiler/compiler", + ["./parser","./compiler/template","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + /*jshint evil:true*/ + var preprocess = __dependency1__.preprocess; + var TemplateCompiler = __dependency2__.TemplateCompiler; + + /* + * Compile a string into a template rendering function + * + * Example usage: + * + * // Template is the hydration portion of the compiled template + * var template = compile("Howdy {{name}}"); + * + * // Template accepts three arguments: + * // + * // 1. A context object + * // 2. An env object + * // 3. A contextualElement (optional, document.body is the default) + * // + * // The env object *must* have at least these two properties: + * // + * // 1. `hooks` - Basic hooks for rendering a template + * // 2. `dom` - An instance of DOMHelper + * // + * import {hooks} from 'htmlbars-runtime'; + * import {DOMHelper} from 'morph'; + * var context = {name: 'whatever'}, + * env = {hooks: hooks, dom: new DOMHelper()}, + * contextualElement = document.body; + * var domFragment = template(context, env, contextualElement); + * + * @method compile + * @param {String} string An htmlbars template string + * @return {Function} A function for rendering the template + */ + function compile(string) { + var program = compileSpec(string); + return new Function("return " + program)(); + } + + __exports__.compile = compile;/* + * Compile a string into a template spec string. The template spec is a string + * representation of a template. Usually, you would use compileSpec for + * pre-compilation of a template on the server. + * + * Example usage: + * + * var templateSpec = compileSpec("Howdy {{name}}"); + * // This next step is basically what plain compile does + * var template = new Function("return " + templateSpec)(); + * + * @method compileSpec + * @param {String} string An htmlbars template string + * @return {Function} A template spec string + */ + function compileSpec(string) { + var ast = preprocess(string); + var compiler = new TemplateCompiler(); + var program = compiler.compile(ast); + return program; + } + + __exports__.compileSpec = compileSpec; + }); +define("htmlbars-compiler/compiler/fragment", + ["./utils","./quoting","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var processOpcodes = __dependency1__.processOpcodes; + var string = __dependency2__.string; + + function FragmentCompiler() { + this.source = []; + this.depth = -1; + } + + __exports__.FragmentCompiler = FragmentCompiler;FragmentCompiler.prototype.compile = function(opcodes, options) { + this.source.length = 0; + this.depth = -1; + this.indent = (options && options.indent) || ""; + + this.source.push(this.indent+'function build(dom) {\n'); + processOpcodes(this, opcodes); + this.source.push(this.indent+'}\n'); + + return this.source.join(''); + }; + + FragmentCompiler.prototype.createFragment = function() { + var el = 'el'+(++this.depth); + this.source.push(this.indent+' var '+el+' = dom.createDocumentFragment();\n'); + }; + + FragmentCompiler.prototype.createElement = function(tagName) { + var el = 'el'+(++this.depth); + this.source.push(this.indent+' var '+el+' = dom.createElement('+string(tagName)+');\n'); + }; + + FragmentCompiler.prototype.createText = function(str) { + var el = 'el'+(++this.depth); + this.source.push(this.indent+' var '+el+' = dom.createTextNode('+string(str)+');\n'); + }; + + FragmentCompiler.prototype.returnNode = function() { + var el = 'el'+this.depth; + this.source.push(this.indent+' return '+el+';\n'); + }; + + FragmentCompiler.prototype.setAttribute = function(name, value) { + var el = 'el'+this.depth; + this.source.push(this.indent+' dom.setAttribute('+el+','+string(name)+','+string(value)+');\n'); + }; + + FragmentCompiler.prototype.appendChild = function() { + var child = 'el'+(this.depth--); + var el = 'el'+this.depth; + this.source.push(this.indent+' dom.appendChild('+el+', '+child+');\n'); + }; + + FragmentCompiler.prototype.setNamespace = function(namespace) { + this.source.push(this.indent+' dom.setNamespace('+(namespace ? string(namespace) : 'null')+');\n'); + }; + }); +define("htmlbars-compiler/compiler/fragment_opcode", + ["./template_visitor","./utils","../utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var TemplateVisitor = __dependency1__["default"]; + var processOpcodes = __dependency2__.processOpcodes; + var forEach = __dependency3__.forEach; + + function FragmentOpcodeCompiler() { + this.opcodes = []; + } + + FragmentOpcodeCompiler.prototype.compile = function(ast) { + var templateVisitor = new TemplateVisitor(); + templateVisitor.visit(ast); + + processOpcodes(this, templateVisitor.actions); + + return this.opcodes; + }; + + FragmentOpcodeCompiler.prototype.opcode = function(type, params) { + this.opcodes.push([type, params]); + }; + + FragmentOpcodeCompiler.prototype.text = function(text, childIndex, childCount, isSingleRoot) { + this.opcode('createText', [text.chars]); + if (!isSingleRoot) { this.opcode('appendChild'); } + }; + + FragmentOpcodeCompiler.prototype.openElement = function(element) { + this.opcode('createElement', [element.tag]); + forEach(element.attributes, this.attribute, this); + }; + + FragmentOpcodeCompiler.prototype.closeElement = function(element, childIndex, childCount, isSingleRoot) { + if (!isSingleRoot) { this.opcode('appendChild'); } + }; + + FragmentOpcodeCompiler.prototype.startProgram = function(program) { + this.opcodes.length = 0; + if (program.statements.length !== 1) { + this.opcode('createFragment'); + } + }; + + FragmentOpcodeCompiler.prototype.endProgram = function(program) { + this.opcode('returnNode'); + }; + + FragmentOpcodeCompiler.prototype.mustache = function () {}; + + FragmentOpcodeCompiler.prototype.component = function () {}; + + FragmentOpcodeCompiler.prototype.block = function () {}; + + FragmentOpcodeCompiler.prototype.attribute = function(attr) { + if (attr.value.type === 'text') { + this.opcode('setAttribute', [attr.name, attr.value.chars]); + } + }; + + FragmentOpcodeCompiler.prototype.setNamespace = function(namespace) { + this.opcode('setNamespace', [namespace]); + }; + + __exports__.FragmentOpcodeCompiler = FragmentOpcodeCompiler; + }); +define("htmlbars-compiler/compiler/helpers", + ["./quoting","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var array = __dependency1__.array; + var hash = __dependency1__.hash; + var string = __dependency1__.string; + + function prepareHelper(stack, size) { + var args = [], + types = [], + hashPairs = [], + hashTypes = [], + keyName, + i; + + var hashSize = stack.pop(); + + for (i=0; i 0){ + this.opcode( 'repairClonedNode', + blankChildTextNodes ); + } + }; + + HydrationOpcodeCompiler.prototype.endProgram = function(program) { + distributeMorphs(this.morphs, this.opcodes); + }; + + HydrationOpcodeCompiler.prototype.text = function(string, pos, len) { + ++this.currentDOMChildIndex; + }; + + HydrationOpcodeCompiler.prototype.openElement = function(element, pos, len, isSingleRoot, mustacheCount, blankChildTextNodes) { + distributeMorphs(this.morphs, this.opcodes); + ++this.currentDOMChildIndex; + + this.element = this.currentDOMChildIndex; + + if (!isSingleRoot) { + this.opcode('consumeParent', this.currentDOMChildIndex); + + // If our parent referance will be used more than once, cache its referance. + if (mustacheCount > 1) { + this.opcode('element', ++this.elementNum); + this.element = null; // Set element to null so we don't cache it twice + } + } + var isElementChecked = detectIsElementChecked(element); + if (blankChildTextNodes.length > 0 || isElementChecked) { + this.opcode( 'repairClonedNode', + blankChildTextNodes, + isElementChecked ); + } + + this.paths.push(this.currentDOMChildIndex); + this.currentDOMChildIndex = -1; + + forEach(element.attributes, this.attribute, this); + forEach(element.helpers, this.nodeHelper, this); + }; + + HydrationOpcodeCompiler.prototype.closeElement = function(element, pos, len, isSingleRoot) { + distributeMorphs(this.morphs, this.opcodes); + if (!isSingleRoot) { this.opcode('popParent'); } + this.currentDOMChildIndex = this.paths.pop(); + }; + + HydrationOpcodeCompiler.prototype.block = function(block, childIndex, childrenLength) { + var currentDOMChildIndex = this.currentDOMChildIndex, + mustache = block.mustache; + + var start = (currentDOMChildIndex < 0 ? null : currentDOMChildIndex), + end = (childIndex === childrenLength - 1 ? null : currentDOMChildIndex + 1); + + var morphNum = this.morphNum++; + this.morphs.push([morphNum, this.paths.slice(), start, end]); + + this.opcode('program', this.templateId++, block.inverse === null ? null : this.templateId++); + processParams(this, mustache.params); + processHash(this, mustache.hash); + this.opcode('helper', mustache.id.string, mustache.params.length, mustache.escaped, morphNum); + }; + + HydrationOpcodeCompiler.prototype.component = function(component, childIndex, childrenLength) { + var currentDOMChildIndex = this.currentDOMChildIndex; + + var start = (currentDOMChildIndex < 0 ? null : currentDOMChildIndex), + end = (childIndex === childrenLength - 1 ? null : currentDOMChildIndex + 1); + + var morphNum = this.morphNum++; + this.morphs.push([morphNum, this.paths.slice(), start, end]); + + this.opcode('program', this.templateId++, null); + processHash(this, buildHashFromAttributes(component.attributes)); + this.opcode('component', component.tag, morphNum); + }; + + HydrationOpcodeCompiler.prototype.opcode = function(type) { + var params = [].slice.call(arguments, 1); + this.opcodes.push([type, params]); + }; + + HydrationOpcodeCompiler.prototype.attribute = function(attr) { + if (attr.value.type === 'text') return; + + // We treat attribute like a attribute helper evaluated by the element hook. + //

+ // Unwrapped any mustaches to just be their internal sexprs. + this.nodeHelper({ + params: [attr.name, attr.value.sexpr], + hash: null, + id: { + string: 'attribute' + } + }); + }; + + HydrationOpcodeCompiler.prototype.nodeHelper = function(mustache) { + this.opcode('program', null, null); + processParams(this, mustache.params); + processHash(this, mustache.hash); + // If we have a helper in a node, and this element has not been cached, cache it + if(this.element !== null){ + this.opcode('element', ++this.elementNum); + this.element = null; // Reset element so we don't cache it more than once + } + this.opcode('nodeHelper', mustache.id.string, mustache.params.length, this.elementNum); + }; + + HydrationOpcodeCompiler.prototype.mustache = function(mustache, childIndex, childrenLength) { + var currentDOMChildIndex = this.currentDOMChildIndex; + + var start = currentDOMChildIndex, + end = (childIndex === childrenLength - 1 ? -1 : currentDOMChildIndex + 1); + + var morphNum = this.morphNum++; + this.morphs.push([morphNum, this.paths.slice(), start, end]); + + if (mustache.isHelper) { + this.opcode('program', null, null); + processParams(this, mustache.params); + processHash(this, mustache.hash); + this.opcode('helper', mustache.id.string, mustache.params.length, mustache.escaped, morphNum); + } else { + this.opcode('ambiguous', mustache.id.string, mustache.escaped, morphNum); + } + }; + + HydrationOpcodeCompiler.prototype.sexpr = function(sexpr) { + this.string('sexpr'); + this.opcode('program', null, null); + processParams(this, sexpr.params); + processHash(this, sexpr.hash); + this.opcode('sexpr', sexpr.id.string, sexpr.params.length); + }; + + HydrationOpcodeCompiler.prototype.string = function(str) { + this.opcode('string', str); + }; + + HydrationOpcodeCompiler.prototype.mustacheInAttr = function(mustache) { + if (mustache.isHelper) { + this.opcode('program', null, null); + processParams(this, mustache.params); + processHash(this, mustache.hash); + this.opcode('helperAttr', mustache.id.string, mustache.params.length, mustache.escaped); + } else { + this.opcode('ambiguousAttr', mustache.id.string, mustache.escaped); + } + }; + + HydrationOpcodeCompiler.prototype.ID = function(id) { + this.opcode('id', id.parts); + }; + + HydrationOpcodeCompiler.prototype.STRING = function(string) { + this.opcode('stringLiteral', string.stringModeValue); + }; + + HydrationOpcodeCompiler.prototype.BOOLEAN = function(boolean) { + this.opcode('literal', boolean.stringModeValue); + }; + + HydrationOpcodeCompiler.prototype.INTEGER = function(integer) { + this.opcode('literal', integer.stringModeValue); + }; + + function processParams(compiler, params) { + forEach(params, function(param) { + if (param.type === 'text') { + compiler.STRING({ stringModeValue: param.chars }); + } else if (param.type) { + compiler[param.type](param); + } else { + compiler.STRING({ stringModeValue: param }); + } + }); + } + + function processHash(compiler, hash) { + if (hash) { + forEach(hash.pairs, function(pair) { + var name = pair[0], param = pair[1]; + compiler[param.type](param); + compiler.opcode('stackLiteral', name); + }); + compiler.opcode('stackLiteral', hash.pairs.length); + } else { + compiler.opcode('stackLiteral', 0); + } + } + + function distributeMorphs(morphs, opcodes) { + if (morphs.length === 0) { + return; + } + + // Splice morphs after the most recent shareParent/consumeParent. + var o; + for (o = opcodes.length - 1; o >= 0; --o) { + var opcode = opcodes[o][0]; + if (opcode === 'element' || opcode === 'consumeParent' || opcode === 'popParent') { + break; + } + } + + var spliceArgs = [o + 1, 0]; + for (var i = 0; i < morphs.length; ++i) { + var p = morphs[i]; + spliceArgs.push(['morph', [p[0], p[1], p[2], p[3]]]); + } + opcodes.splice.apply(opcodes, spliceArgs); + morphs.length = 0; + } + + __exports__.HydrationOpcodeCompiler = HydrationOpcodeCompiler; + }); +define("htmlbars-compiler/compiler/quoting", + ["exports"], + function(__exports__) { + "use strict"; + function escapeString(str) { + return str.replace(/"/g, '\\"').replace(/\n/g, "\\n"); + } + + __exports__.escapeString = escapeString; + + function string(str) { + return '"' + escapeString(str) + '"'; + } + + __exports__.string = string; + + function array(a) { + return "[" + a + "]"; + } + + __exports__.array = array; + + function quotedArray(list) { + return array(list.map(string).join(", ")); + } + + __exports__.quotedArray = quotedArray;function hash(pairs) { + return "{" + pairs.join(",") + "}"; + } + + __exports__.hash = hash;function repeat(chars, times) { + var str = ""; + while (times--) { + str += chars; + } + return str; + } + + __exports__.repeat = repeat; + }); +define("htmlbars-compiler/compiler/template", + ["./fragment_opcode","./fragment","./hydration_opcode","./hydration","./template_visitor","./utils","./quoting","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var FragmentOpcodeCompiler = __dependency1__.FragmentOpcodeCompiler; + var FragmentCompiler = __dependency2__.FragmentCompiler; + var HydrationOpcodeCompiler = __dependency3__.HydrationOpcodeCompiler; + var HydrationCompiler = __dependency4__.HydrationCompiler; + var TemplateVisitor = __dependency5__["default"]; + var processOpcodes = __dependency6__.processOpcodes; + var string = __dependency7__.string; + var repeat = __dependency7__.repeat; + + function TemplateCompiler() { + this.fragmentOpcodeCompiler = new FragmentOpcodeCompiler(); + this.fragmentCompiler = new FragmentCompiler(); + this.hydrationOpcodeCompiler = new HydrationOpcodeCompiler(); + this.hydrationCompiler = new HydrationCompiler(); + this.templates = []; + this.childTemplates = []; + } + + __exports__.TemplateCompiler = TemplateCompiler;TemplateCompiler.prototype.compile = function(ast) { + var templateVisitor = new TemplateVisitor(); + templateVisitor.visit(ast); + + processOpcodes(this, templateVisitor.actions); + + return this.templates.pop(); + }; + + TemplateCompiler.prototype.startProgram = function(program, childTemplateCount, blankChildTextNodes) { + this.fragmentOpcodeCompiler.startProgram(program, childTemplateCount, blankChildTextNodes); + this.hydrationOpcodeCompiler.startProgram(program, childTemplateCount, blankChildTextNodes); + + this.childTemplates.length = 0; + while(childTemplateCount--) { + this.childTemplates.push(this.templates.pop()); + } + }; + + TemplateCompiler.prototype.endProgram = function(program, programDepth) { + this.fragmentOpcodeCompiler.endProgram(program); + this.hydrationOpcodeCompiler.endProgram(program); + + var indent = repeat(" ", programDepth); + var options = { + indent: indent + " " + }; + + // function build(dom) { return fragment; } + var fragmentProgram = this.fragmentCompiler.compile( + this.fragmentOpcodeCompiler.opcodes, + options + ); + + // function hydrate(fragment) { return mustaches; } + var hydrationProgram = this.hydrationCompiler.compile( + this.hydrationOpcodeCompiler.opcodes, + options + ); + + var childTemplateVars = ""; + for (var i=0, l=this.childTemplates.length; ibaz + * + * produces the actions + * + * [['startProgram', [programNode, 0]], + * ['text', [textNode, 0, 3]], + * ['mustache', [mustacheNode, 1, 3]], + * ['openElement', [elementNode, 2, 3, 0]], + * ['text', [textNode, 0, 1]], + * ['closeElement', [elementNode, 2, 3], + * ['endProgram', [programNode]]] + * + * This visitor walks the AST depth first and backwards. As + * a result the bottom-most child template will appear at the + * top of the actions list whereas the root template will appear + * at the bottom of the list. For example, + * + *
{{#if}}foo{{else}}bar{{/if}}
+ * + * produces the actions + * + * [['startProgram', [programNode, 0]], + * ['text', [textNode, 0, 2, 0]], + * ['openElement', [elementNode, 1, 2, 0]], + * ['closeElement', [elementNode, 1, 2]], + * ['endProgram', [programNode]], + * ['startProgram', [programNode, 0]], + * ['text', [textNode, 0, 1]], + * ['endProgram', [programNode]], + * ['startProgram', [programNode, 2]], + * ['openElement', [elementNode, 0, 1, 1]], + * ['block', [blockNode, 0, 1]], + * ['closeElement', [elementNode, 0, 1]], + * ['endProgram', [programNode]]] + * + * The state of the traversal is maintained by a stack of frames. + * Whenever a node with children is entered (either a ProgramNode + * or an ElementNode) a frame is pushed onto the stack. The frame + * contains information about the state of the traversal of that + * node. For example, + * + * - index of the current child node being visited + * - the number of mustaches contained within its child nodes + * - the list of actions generated by its child nodes + */ + + function TemplateVisitor() { + this.frameStack = []; + this.actions = []; + this.programDepth = -1; + } + + // Traversal methods + + TemplateVisitor.prototype.visit = function(node) { + this[node.type](node); + }; + + TemplateVisitor.prototype.program = function(program) { + this.programDepth++; + + var parentFrame = this.getCurrentFrame(); + var programFrame = this.pushFrame(); + + programFrame.parentNode = program; + programFrame.children = program.statements; + programFrame.childCount = program.statements.length; + programFrame.blankChildTextNodes = []; + programFrame.actions.push(['endProgram', [program, this.programDepth]]); + + for (var i = program.statements.length - 1; i >= 0; i--) { + programFrame.childIndex = i; + this.visit(program.statements[i]); + } + + programFrame.actions.push(['startProgram', [ + program, programFrame.childTemplateCount, programFrame.blankChildTextNodes.reverse() ]]); + this.popFrame(); + + this.programDepth--; + + // Push the completed template into the global actions list + if (parentFrame) { parentFrame.childTemplateCount++; } + push.apply(this.actions, programFrame.actions.reverse()); + }; + + TemplateVisitor.prototype.element = function(element) { + var parentFrame = this.getCurrentFrame(); + var elementFrame = this.pushFrame(); + var parentNode = parentFrame.parentNode; + + elementFrame.parentNode = element; + elementFrame.children = element.children; + elementFrame.childCount = element.children.length; + elementFrame.mustacheCount += element.helpers.length; + elementFrame.blankChildTextNodes = []; + + var actionArgs = [ + element, + parentFrame.childIndex, + parentFrame.childCount, + parentNode.type === 'program' && parentFrame.childCount === 1 + ]; + + var lastNode = parentFrame.childIndex === parentFrame.childCount-1, + introducesNamespace = elementIntroducesNamespace(element, parentFrame.parentNode); + if ( !lastNode && introducesNamespace ) { + elementFrame.actions.push(['setNamespace', [parentNode.namespaceURI]]); + } + elementFrame.actions.push(['closeElement', actionArgs]); + if ( !lastNode && element.isHTMLIntergrationPoint ) { + elementFrame.actions.push(['setNamespace', []]); + } + + for (var i = element.attributes.length - 1; i >= 0; i--) { + this.visit(element.attributes[i]); + } + + for (i = element.children.length - 1; i >= 0; i--) { + elementFrame.childIndex = i; + this.visit(element.children[i]); + } + + if ( element.isHTMLIntergrationPoint ) { + elementFrame.actions.push(['setNamespace', []]); + } + elementFrame.actions.push(['openElement', actionArgs.concat([ + elementFrame.mustacheCount, elementFrame.blankChildTextNodes.reverse() ])]); + if ( introducesNamespace ) { + elementFrame.actions.push(['setNamespace', [element.namespaceURI]]); + } + this.popFrame(); + + // Propagate the element's frame state to the parent frame + if (elementFrame.mustacheCount > 0) { parentFrame.mustacheCount++; } + parentFrame.childTemplateCount += elementFrame.childTemplateCount; + push.apply(parentFrame.actions, elementFrame.actions); + }; + + TemplateVisitor.prototype.attr = function(attr) { + if (attr.value.type === 'mustache') { + this.getCurrentFrame().mustacheCount++; + } + }; + + TemplateVisitor.prototype.block = function(node) { + var frame = this.getCurrentFrame(); + var parentNode = frame.parentNode; + + frame.mustacheCount++; + frame.actions.push([node.type, [node, frame.childIndex, frame.childCount]]); + + if (node.inverse) { this.visit(node.inverse); } + if (node.program) { this.visit(node.program); } + }; + + TemplateVisitor.prototype.partial = function(node) { + var frame = this.getCurrentFrame(); + frame.mustacheCount++; + frame.actions.push(['mustache', [node, frame.childIndex, frame.childCount]]); + }; + + TemplateVisitor.prototype.component = TemplateVisitor.prototype.block; + + TemplateVisitor.prototype.text = function(text) { + var frame = this.getCurrentFrame(); + var isSingleRoot = frame.parentNode.type === 'program' && frame.childCount === 1; + if (text.chars === '') { + frame.blankChildTextNodes.push(domIndexOf(frame.children, text)); + } + frame.actions.push(['text', [text, frame.childIndex, frame.childCount, isSingleRoot]]); + }; + + TemplateVisitor.prototype.mustache = function(mustache) { + var frame = this.getCurrentFrame(); + frame.mustacheCount++; + frame.actions.push(['mustache', [mustache, frame.childIndex, frame.childCount]]); + }; + + // Frame helpers + + TemplateVisitor.prototype.getCurrentFrame = function() { + return this.frameStack[this.frameStack.length - 1]; + }; + + TemplateVisitor.prototype.pushFrame = function() { + var frame = new Frame(); + this.frameStack.push(frame); + return frame; + }; + + TemplateVisitor.prototype.popFrame = function() { + return this.frameStack.pop(); + }; + + __exports__["default"] = TemplateVisitor; + + + // Returns the index of `domNode` in the `nodes` array, skipping + // over any nodes which do not represent DOM nodes. + function domIndexOf(nodes, domNode) { + var index = -1; + + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; + + if (node.type !== 'text' && node.type !== 'element') { + continue; + } else { + index++; + } + + if (node === domNode) { + return index; + } + } + + return -1; + } + }); +define("htmlbars-compiler/compiler/utils", + ["exports"], + function(__exports__) { + "use strict"; + function processOpcodes(compiler, opcodes) { + for (var i=0, l=opcodes.length; i 0 && statements[i-1].strip && statements[i-1].strip.right) || + (i === 0 && program.strip.left)) { + statement.chars = statement.chars.replace(/^\s+/, ''); + } + + if ((i < l-1 && statements[i+1].strip && statements[i+1].strip.left) || + (i === l-1 && program.strip.right)) { + statement.chars = statement.chars.replace(/\s+$/, ''); + } + + // Remove unnecessary text nodes + if (statement.chars.length === 0) { + if ((i > 0 && statements[i-1].type === 'element') || + (i < l-1 && statements[i+1].type === 'element')) { + statements.splice(i, 1); + i--; + l--; + } + } + } + } + + __exports__.postprocessProgram = postprocessProgram; + }); +define("htmlbars-compiler/html-parser/node-handlers", + ["../ast","../html-parser/helpers","../html-parser/tokens","../utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var BlockNode = __dependency1__.BlockNode; + var ProgramNode = __dependency1__.ProgramNode; + var TextNode = __dependency1__.TextNode; + var PartialNode = __dependency1__.PartialNode; + var appendChild = __dependency1__.appendChild; + var usesMorph = __dependency1__.usesMorph; + var postprocessProgram = __dependency2__.postprocessProgram; + var Chars = __dependency3__.Chars; + var forEach = __dependency4__.forEach; + + var nodeHandlers = { + + program: function(program) { + var statements = []; + var node = new ProgramNode(statements, program.strip); + var i, l = program.statements.length; + + this.elementStack.push(node); + + if (l === 0) { return this.elementStack.pop(); } + + for (i = 0; i < l; i++) { + this.acceptNode(program.statements[i]); + } + + this.acceptToken(this.tokenizer.tokenizeEOF()); + + postprocessProgram(node); + + // Ensure that that the element stack is balanced properly. + var poppedNode = this.elementStack.pop(); + if (poppedNode !== node) { + throw new Error("Unclosed element: " + poppedNode.tag); + } + + return node; + }, + + block: function(block) { + switchToHandlebars(this); + this.acceptToken(block); + + var mustache = block.mustache; + var program = this.acceptNode(block.program); + var inverse = block.inverse ? this.acceptNode(block.inverse) : null; + var strip = block.strip; + + // Normalize inverse's strip + if (inverse && !inverse.strip.left) { + inverse.strip.left = false; + } + + var node = new BlockNode(mustache, program, inverse, strip); + var parentProgram = this.currentElement(); + appendChild(parentProgram, node); + }, + + content: function(content) { + var tokens = this.tokenizer.tokenizePart(content.string); + + return forEach(tokens, this.acceptToken, this); + }, + + mustache: function(mustache) { + switchToHandlebars(this); + this.acceptToken(mustache); + }, + + comment: function(comment) { + return; + }, + + partial: function(partial) { + var node = new PartialNode(partial.partialName.name); + appendChild(this.currentElement(), node); + return; + } + }; + + function switchToHandlebars(processor) { + var token = processor.tokenizer.token; + + // TODO: Monkey patch Chars.addChar like attributes + if (token instanceof Chars) { + processor.acceptToken(token); + processor.tokenizer.token = null; + } + } + + __exports__["default"] = nodeHandlers; + }); +define("htmlbars-compiler/html-parser/token-handlers", + ["../ast","./helpers","../utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var ProgramNode = __dependency1__.ProgramNode; + var ComponentNode = __dependency1__.ComponentNode; + var ElementNode = __dependency1__.ElementNode; + var TextNode = __dependency1__.TextNode; + var appendChild = __dependency1__.appendChild; + var postprocessProgram = __dependency2__.postprocessProgram; + var forEach = __dependency3__.forEach; + + // This table maps from the state names in the tokenizer to a smaller + // number of states that control how mustaches are handled + var states = { + "beforeAttributeValue": "before-attr", + "attributeValueDoubleQuoted": "attr", + "attributeValueSingleQuoted": "attr", + "attributeValueUnquoted": "attr", + "beforeAttributeName": "in-tag" + }; + + // The HTML elements in this list are speced by + // http://www.w3.org/TR/html-markup/syntax.html#syntax-elements, + // and will be forced to close regardless of if they have a + // self-closing /> at the end. + var voidTagNames = "area base br col command embed hr img input keygen link meta param source track wbr"; + var voidMap = {}; + + forEach(voidTagNames.split(" "), function(tagName) { + voidMap[tagName] = true; + }); + + var svgNamespace = "http://www.w3.org/2000/svg", + // http://www.w3.org/html/wg/drafts/html/master/syntax.html#html-integration-point + svgHTMLIntegrationPoints = {'foreignObject':true, 'desc':true, 'title':true}; + + function applyNamespace(tag, element, currentElement){ + if (tag.tagName === 'svg') { + element.namespaceURI = svgNamespace; + } else if ( + currentElement.type === 'element' && + currentElement.namespaceURI && + !currentElement.isHTMLIntegrationPoint + ) { + element.namespaceURI = currentElement.namespaceURI; + } + } + + function applyHTMLIntegrationPoint(tag, element){ + if (svgHTMLIntegrationPoints[tag.tagName]) { + element.isHTMLIntegrationPoint = true; + } + } + + + // Except for `mustache`, all tokens are only allowed outside of + // a start or end tag. + var tokenHandlers = { + + Chars: function(token) { + var current = this.currentElement(); + var text = new TextNode(token.chars); + appendChild(current, text); + }, + + StartTag: function(tag) { + var element = new ElementNode(tag.tagName, tag.attributes, tag.helpers || [], []); + applyNamespace(tag, element, this.currentElement()); + applyHTMLIntegrationPoint(tag, element); + this.elementStack.push(element); + if (voidMap.hasOwnProperty(tag.tagName) || tag.selfClosing) { + tokenHandlers.EndTag.call(this, tag); + } + }, + + block: function(block) { + if (this.tokenizer.state !== 'data') { + throw new Error("A block may only be used inside an HTML element or another block."); + } + }, + + mustache: function(mustache) { + var state = this.tokenizer.state; + var token = this.tokenizer.token; + + switch(states[state]) { + case "before-attr": + this.tokenizer.state = 'attributeValueUnquoted'; + token.addToAttributeValue(mustache); + return; + case "attr": + token.addToAttributeValue(mustache); + return; + case "in-tag": + token.addTagHelper(mustache); + return; + default: + appendChild(this.currentElement(), mustache); + } + }, + + EndTag: function(tag) { + var element = this.elementStack.pop(); + var parent = this.currentElement(); + + if (element.tag !== tag.tagName) { + throw new Error("Closing tag " + tag.tagName + " did not match last open tag " + element.tag); + } + + if (element.tag.indexOf("-") === -1) { + appendChild(parent, element); + } else { + var program = new ProgramNode(element.children, { left: false, right: false }); + postprocessProgram(program); + var component = new ComponentNode(element.tag, element.attributes, program); + appendChild(parent, component); + } + + } + + }; + + __exports__["default"] = tokenHandlers; + }); +define("htmlbars-compiler/html-parser/tokens", + ["../../simple-html-tokenizer","../ast","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Chars = __dependency1__.Chars; + var StartTag = __dependency1__.StartTag; + var EndTag = __dependency1__.EndTag; + var AttrNode = __dependency2__.AttrNode; + var TextNode = __dependency2__.TextNode; + var MustacheNode = __dependency2__.MustacheNode; + var StringNode = __dependency2__.StringNode; + var IdNode = __dependency2__.IdNode; + + StartTag.prototype.startAttribute = function(char) { + this.finalizeAttributeValue(); + this.currentAttribute = new AttrNode(char.toLowerCase(), []); + this.attributes.push(this.currentAttribute); + }; + + StartTag.prototype.addToAttributeName = function(char) { + this.currentAttribute.name += char; + }; + + StartTag.prototype.addToAttributeValue = function(char) { + var value = this.currentAttribute.value; + + if (char.type === 'mustache') { + value.push(char); + } else { + if (value.length > 0 && value[value.length - 1].type === 'text') { + value[value.length - 1].chars += char; + } else { + value.push(new TextNode(char)); + } + } + }; + + StartTag.prototype.finalize = function() { + this.finalizeAttributeValue(); + delete this.currentAttribute; + return this; + }; + + StartTag.prototype.finalizeAttributeValue = function() { + var attr = this.currentAttribute; + + if (!attr) return; + + if (attr.value.length === 1) { + // Unwrap a single TextNode or MustacheNode + attr.value = attr.value[0]; + } else { + // If the attr value has multiple parts combine them into + // a single MustacheNode with the concat helper + var params = [ new IdNode([{ part: 'concat' }]) ]; + + for (var i = 0; i < attr.value.length; i++) { + var part = attr.value[i]; + if (part.type === 'text') { + params.push(new StringNode(part.chars)); + } else if (part.type === 'mustache') { + var sexpr = part.sexpr; + delete sexpr.isRoot; + + if (sexpr.isHelper) { + sexpr.isHelper = true; + } + + params.push(sexpr); + } + } + + attr.value = new MustacheNode(params, undefined, true, { left: false, right: false }); + } + }; + + StartTag.prototype.addTagHelper = function(helper) { + var helpers = this.helpers = this.helpers || []; + helpers.push(helper); + }; + + __exports__.Chars = Chars; + __exports__.StartTag = StartTag; + __exports__.EndTag = EndTag; + }); +define("htmlbars-compiler/parser", + ["../handlebars/compiler/base","../simple-html-tokenizer","./html-parser/node-handlers","./html-parser/token-handlers","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var parse = __dependency1__.parse; + var Tokenizer = __dependency2__.Tokenizer; + var nodeHandlers = __dependency3__["default"]; + var tokenHandlers = __dependency4__["default"]; + + function preprocess(html, options) { + var ast = parse(html); + var combined = new HTMLProcessor().acceptNode(ast); + return combined; + } + + __exports__.preprocess = preprocess;function HTMLProcessor() { + this.elementStack = []; + this.tokenizer = new Tokenizer(''); + this.nodeHandlers = nodeHandlers; + this.tokenHandlers = tokenHandlers; + } + + HTMLProcessor.prototype.acceptNode = function(node) { + return this.nodeHandlers[node.type].call(this, node); + }; + + HTMLProcessor.prototype.acceptToken = function(token) { + if (token) { + return this.tokenHandlers[token.type].call(this, token); + } + }; + + HTMLProcessor.prototype.currentElement = function() { + return this.elementStack[this.elementStack.length - 1]; + }; + }); +define("htmlbars-compiler/utils", + ["exports"], + function(__exports__) { + "use strict"; + function forEach(array, callback, binding) { + var i, l; + if (binding === undefined) { + for (i=0, l=array.length; i + // + // + // + // The tbody may be omitted, and the browser will accept and render: + // + // + // + // + // However, the omitted start tag will still be added to the DOM. Here + // we test the string and context to see if the browser is about to + // perform this cleanup. + // + // http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#optional-tags + // describes which tags are omittable. The spec for tbody and colgroup + // explains this behavior: + // + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-tbody-element + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-colgroup-element + // + + var omittedStartTagChildTest = /<([\w:]+)/; + function detectOmittedStartTag(string, contextualElement){ + // Omitted start tags are only inside table tags. + if (contextualElement.tagName === 'TABLE') { + var omittedStartTagChildMatch = omittedStartTagChildTest.exec(string); + if (omittedStartTagChildMatch) { + var omittedStartTagChild = omittedStartTagChildMatch[1]; + // It is already asserted that the contextual element is a table + // and not the proper start tag. Just see if a tag was omitted. + return omittedStartTagChild === 'tr' || + omittedStartTagChild === 'col'; + } + } + } + + function buildSVGDOM(html, dom){ + var div = dom.document.createElement('div'); + div.innerHTML = ''+html+''; + return div.firstChild.childNodes; + } + + /* + * A class wrapping DOM functions to address environment compatibility, + * namespaces, contextual elements for morph un-escaped content + * insertion. + * + * When entering a template, a DOMHelper should be passed: + * + * template(context, { hooks: hooks, dom: new DOMHelper() }); + * + * TODO: support foreignObject as a passed contextual element. It has + * a namespace (svg) that does not match its internal namespace + * (xhtml). + * + * @class DOMHelper + * @constructor + * @param {HTMLDocument} _document The document DOM methods are proxied to + */ + function DOMHelper(_document){ + this.document = _document || window.document; + this.namespace = null; + } + + var prototype = DOMHelper.prototype; + prototype.constructor = DOMHelper; + + prototype.insertBefore = function(element, childElement, referenceChild) { + return element.insertBefore(childElement, referenceChild); + }; + + prototype.appendChild = function(element, childElement) { + return element.appendChild(childElement); + }; + + prototype.appendText = function(element, text) { + return element.appendChild(this.document.createTextNode(text)); + }; + + prototype.setAttribute = function(element, name, value) { + element.setAttribute(name, value); + }; + + if (document.createElementNS) { + // Only opt into namespace detection if a contextualElement + // is passed. + prototype.createElement = function(tagName, contextualElement) { + var namespace = this.namespace; + if (contextualElement) { + if (tagName === 'svg') { + namespace = svgNamespace; + } else { + namespace = interiorNamespace(contextualElement); + } + } + if (namespace) { + return this.document.createElementNS(namespace, tagName); + } else { + return this.document.createElement(tagName); + } + }; + } else { + prototype.createElement = function(tagName) { + return this.document.createElement(tagName); + }; + } + + prototype.setNamespace = function(ns) { + this.namespace = ns; + }; + + prototype.detectNamespace = function(element) { + this.namespace = interiorNamespace(element); + }; + + prototype.createDocumentFragment = function(){ + return this.document.createDocumentFragment(); + }; + + prototype.createTextNode = function(text){ + return this.document.createTextNode(text); + }; + + prototype.repairClonedNode = function(element, blankChildTextNodes, isChecked){ + if (deletesBlankTextNodes && blankChildTextNodes.length > 0) { + for (var i=0, len=blankChildTextNodes.length;i]*)>", 'i'))[0]; + var endTag = ''; + + var wrappedHTML = [startTag, html, endTag]; + + var i = wrappingTags.length; + var wrappedDepth = 1 + i; + while(i--) { + wrappedHTML.unshift('<'+wrappingTags[i]+'>'); + wrappedHTML.push(''); + } + + var wrapper = document.createElement('div'); + scriptSafeInnerHTML(wrapper, wrappedHTML.join('')); + var element = wrapper; + while (wrappedDepth--) { + element = element.firstChild; + while (element && element.nodeType !== 1) { + element = element.nextSibling; + } + } + while (element && element.tagName !== tagName) { + element = element.nextSibling; + } + return element ? element.childNodes : []; + } + + var buildDOM; + if (needsShy) { + buildDOM = function buildDOM(html, contextualElement, dom){ + contextualElement = dom.cloneNode(contextualElement, false); + scriptSafeInnerHTML(contextualElement, html); + return contextualElement.childNodes; + }; + } else { + buildDOM = function buildDOM(html, contextualElement, dom){ + contextualElement = dom.cloneNode(contextualElement, false); + contextualElement.innerHTML = html; + return contextualElement.childNodes; + }; + } + + + var buildIESafeDOM; + if (tagNamesRequiringInnerHTMLFix.length > 0 || movesWhitespace) { + buildIESafeDOM = function buildIESafeDOM(html, contextualElement, dom) { + // Make a list of the leading text on script nodes. Include + // script tags without any whitespace for easier processing later. + var spacesBefore = []; + var spacesAfter = []; + html = html.replace(/(\s*)()(\s*)/g, function(match, tag, spaces) { + spacesAfter.push(spaces); + return tag; + }); + + // Fetch nodes + var nodes; + if (tagNamesRequiringInnerHTMLFix[contextualElement.tagName.toLowerCase()]) { + // buildDOMWithFix uses string wrappers for problematic innerHTML. + nodes = buildDOMWithFix(html, contextualElement); + } else { + nodes = buildDOM(html, contextualElement, dom); + } + + // Build a list of script tags, the nodes themselves will be + // mutated as we add test nodes. + var i, j, node, nodeScriptNodes; + var scriptNodes = []; + for (i=0;node=nodes[i];i++) { + if (node.nodeType !== 1) { + continue; + } + if (node.tagName === 'SCRIPT') { + scriptNodes.push(node); + } else { + nodeScriptNodes = node.getElementsByTagName('script'); + for (j=0;j 0) { + textNode = dom.document.createTextNode(spaceBefore); + scriptNode.parentNode.insertBefore(textNode, scriptNode); + } + + spaceAfter = spacesAfter[i]; + if (spaceAfter && spaceAfter.length > 0) { + textNode = dom.document.createTextNode(spaceAfter); + scriptNode.parentNode.insertBefore(textNode, scriptNode.nextSibling); + } + } + + return nodes; + }; + } else { + buildIESafeDOM = buildDOM; + } + + var buildHTMLDOM; + if (needsIntegrationPointFix) { + buildHTMLDOM = function buildHTMLDOM(html, contextualElement, dom){ + if (svgHTMLIntegrationPoints[contextualElement.tagName]) { + return buildIESafeDOM(html, document.createElement('div'), dom); + } else { + return buildIESafeDOM(html, contextualElement, dom); + } + }; + } else { + buildHTMLDOM = buildIESafeDOM; + } + + __exports__.buildHTMLDOM = buildHTMLDOM; + }); +define("morph/morph", + ["exports"], + function(__exports__) { + "use strict"; + var splice = Array.prototype.splice; + + function ensureStartEnd(start, end) { + if (start === null || end === null) { + throw new Error('a fragment parent must have boundary nodes in order to detect insertion'); + } + } + + function ensureContext(contextualElement) { + if (!contextualElement || contextualElement.nodeType !== 1) { + throw new Error('An element node must be provided for a contextualElement, you provided ' + + (contextualElement ? 'nodeType ' + contextualElement.nodeType : 'nothing')); + } + } + + // TODO: this is an internal API, this should be an assert + function Morph(parent, start, end, domHelper, contextualElement) { + if (parent.nodeType === 11) { + ensureStartEnd(start, end); + this.element = null; + } else { + this.element = parent; + } + this._parent = parent; + this.start = start; + this.end = end; + this.domHelper = domHelper; + ensureContext(contextualElement); + this.contextualElement = contextualElement; + this.reset(); + } + + Morph.prototype.reset = function() { + this.text = null; + this.owner = null; + this.morphs = null; + this.before = null; + this.after = null; + this.escaped = true; + }; + + Morph.prototype.parent = function () { + if (!this.element) { + var parent = this.start.parentNode; + if (this._parent !== parent) { + this.element = this._parent = parent; + } + } + return this._parent; + }; + + Morph.prototype.destroy = function () { + if (this.owner) { + this.owner.removeMorph(this); + } else { + clear(this.element || this.parent(), this.start, this.end); + } + }; + + Morph.prototype.removeMorph = function (morph) { + var morphs = this.morphs; + for (var i=0, l=morphs.length; i 0 ? morphs[index-1] : null; + var after = index < morphs.length ? morphs[index] : null; + var start = before === null ? this.start : (before.end === null ? parent.lastChild : before.end.previousSibling); + var end = after === null ? this.end : (after.start === null ? parent.firstChild : after.start.nextSibling); + var morph = new Morph(parent, start, end, this.domHelper, this.contextualElement); + + morph.owner = this; + morph._update(parent, node); + + if (before !== null) { + morph.before = before; + before.end = start.nextSibling; + before.after = morph; + } + + if (after !== null) { + morph.after = after; + after.before = morph; + after.start = end.previousSibling; + } + + this.morphs.splice(index, 0, morph); + return morph; + }; + + Morph.prototype.replace = function (index, removedLength, addedNodes) { + if (this.morphs === null) this.morphs = []; + var parent = this.element || this.parent(); + var morphs = this.morphs; + var before = index > 0 ? morphs[index-1] : null; + var after = index+removedLength < morphs.length ? morphs[index+removedLength] : null; + var start = before === null ? this.start : (before.end === null ? parent.lastChild : before.end.previousSibling); + var end = after === null ? this.end : (after.start === null ? parent.firstChild : after.start.nextSibling); + var addedLength = addedNodes === undefined ? 0 : addedNodes.length; + var args, i, current; + + if (removedLength > 0) { + clear(parent, start, end); + } + + if (addedLength === 0) { + if (before !== null) { + before.after = after; + before.end = end; + } + if (after !== null) { + after.before = before; + after.start = start; + } + morphs.splice(index, removedLength); + return; + } + + args = new Array(addedLength+2); + if (addedLength > 0) { + for (i=0; i") { + return this.emitToken(); + } else { + this.addToComment(char); + this.state = 'comment'; + } + }, + + commentStartDash: function(char) { + if (char === "-") { + this.state = 'commentEnd'; + } else if (char === ">") { + return this.emitToken(); + } else { + this.addToComment("-"); + this.state = 'comment'; + } + }, + + comment: function(char) { + if (char === "-") { + this.state = 'commentEndDash'; + } else { + this.addToComment(char); + } + }, + + commentEndDash: function(char) { + if (char === "-") { + this.state = 'commentEnd'; + } else { + this.addToComment("-" + char); + this.state = 'comment'; + } + }, + + commentEnd: function(char) { + if (char === ">") { + return this.emitToken(); + } else { + this.addToComment("--" + char); + this.state = 'comment'; + } + }, + + tagName: function(char) { + if (isSpace(char)) { + this.state = 'beforeAttributeName'; + } else if (char === "/") { + this.state = 'selfClosingStartTag'; + } else if (char === ">") { + return this.emitToken(); + } else { + this.token.addToTagName(char); + } + }, + + beforeAttributeName: function(char) { + if (isSpace(char)) { + return; + } else if (char === "/") { + this.state = 'selfClosingStartTag'; + } else if (char === ">") { + return this.emitToken(); + } else { + this.attribute(char); + } + }, + + attributeName: function(char) { + if (isSpace(char)) { + this.state = 'afterAttributeName'; + } else if (char === "/") { + this.state = 'selfClosingStartTag'; + } else if (char === "=") { + this.state = 'beforeAttributeValue'; + } else if (char === ">") { + return this.emitToken(); + } else { + this.addToAttributeName(char); + } + }, + + afterAttributeName: function(char) { + if (isSpace(char)) { + return; + } else if (char === "/") { + this.state = 'selfClosingStartTag'; + } else if (char === "=") { + this.state = 'beforeAttributeValue'; + } else if (char === ">") { + return this.emitToken(); + } else { + this.attribute(char); + } + }, + + beforeAttributeValue: function(char) { + if (isSpace(char)) { + return; + } else if (char === '"') { + this.state = 'attributeValueDoubleQuoted'; + } else if (char === "'") { + this.state = 'attributeValueSingleQuoted'; + } else if (char === ">") { + return this.emitToken(); + } else { + this.state = 'attributeValueUnquoted'; + this.addToAttributeValue(char); + } + }, + + attributeValueDoubleQuoted: function(char) { + if (char === '"') { + this.state = 'afterAttributeValueQuoted'; + } else if (char === "&") { + this.addToAttributeValue(this.consumeCharRef('"') || "&"); + } else { + this.addToAttributeValue(char); + } + }, + + attributeValueSingleQuoted: function(char) { + if (char === "'") { + this.state = 'afterAttributeValueQuoted'; + } else if (char === "&") { + this.addToAttributeValue(this.consumeCharRef("'") || "&"); + } else { + this.addToAttributeValue(char); + } + }, + + attributeValueUnquoted: function(char) { + if (isSpace(char)) { + this.state = 'beforeAttributeName'; + } else if (char === "&") { + this.addToAttributeValue(this.consumeCharRef(">") || "&"); + } else if (char === ">") { + return this.emitToken(); + } else { + this.addToAttributeValue(char); + } + }, + + afterAttributeValueQuoted: function(char) { + if (isSpace(char)) { + this.state = 'beforeAttributeName'; + } else if (char === "/") { + this.state = 'selfClosingStartTag'; + } else if (char === ">") { + return this.emitToken(); + } else { + this.char--; + this.state = 'beforeAttributeName'; + } + }, + + selfClosingStartTag: function(char) { + if (char === ">") { + this.selfClosing(); + return this.emitToken(); + } else { + this.char--; + this.state = 'beforeAttributeName'; + } + }, + + endTagOpen: function(char) { + if (isAlpha(char)) { + this.tag(EndTag, char.toLowerCase()); + } + } + } + }; + + function Tag(tagName, attributes, options) { + this.tagName = tagName || ""; + this.attributes = attributes || []; + this.selfClosing = options ? options.selfClosing : false; + } + + Tag.prototype = { + constructor: Tag, + + addToTagName: function(char) { + this.tagName += char; + }, + + startAttribute: function(char) { + this.currentAttribute = [char.toLowerCase(), null]; + this.attributes.push(this.currentAttribute); + }, + + addToAttributeName: function(char) { + this.currentAttribute[0] += char; + }, + + addToAttributeValue: function(char) { + this.currentAttribute[1] = this.currentAttribute[1] || ""; + this.currentAttribute[1] += char; + }, + + finalize: function() { + delete this.currentAttribute; + return this; + } + }; + + function StartTag() { + Tag.apply(this, arguments); + } + + StartTag.prototype = objectCreate(Tag.prototype); + StartTag.prototype.type = 'StartTag'; + StartTag.prototype.constructor = StartTag; + + StartTag.prototype.toHTML = function() { + return config.generateTag(this); + }; + + function generateTag(tag) { + var out = "<"; + out += tag.tagName; + + if (tag.attributes.length) { + out += " " + config.generateAttributes(tag.attributes); + } + + out += ">"; + + return out; + } + + function generateAttributes(attributes) { + var out = [], attribute, attrString, value; + + for (var i=0, l=attributes.length; i"; + } + }; + + function tokenize(input) { + var tokenizer = new Tokenizer(input); + return tokenizer.tokenize(); + } + + function generate(tokens) { + var output = ""; + + for (var i=0, l=tokens.length; i= 1.0.0' + }; + __exports__.REVISION_CHANGES = REVISION_CHANGES; + var isArray = Utils.isArray, + isFunction = Utils.isFunction, + toString = Utils.toString, + objectType = '[object Object]'; + + function HandlebarsEnvironment(helpers, partials) { + this.helpers = helpers || {}; + this.partials = partials || {}; + + registerDefaultHelpers(this); + } + + __exports__.HandlebarsEnvironment = HandlebarsEnvironment;HandlebarsEnvironment.prototype = { + constructor: HandlebarsEnvironment, + + logger: logger, + log: log, + + registerHelper: function(name, fn, inverse) { + if (toString.call(name) === objectType) { + if (inverse || fn) { throw new Exception('Arg not supported with multiple helpers'); } + Utils.extend(this.helpers, name); + } else { + if (inverse) { fn.not = inverse; } + this.helpers[name] = fn; + } + }, + + registerPartial: function(name, str) { + if (toString.call(name) === objectType) { + Utils.extend(this.partials, name); + } else { + this.partials[name] = str; + } + } + }; + + function registerDefaultHelpers(instance) { + instance.registerHelper('helperMissing', function(arg) { + if(arguments.length === 2) { + return undefined; + } else { + throw new Exception("Missing helper: '" + arg + "'"); + } + }); + + instance.registerHelper('blockHelperMissing', function(context, options) { + var inverse = options.inverse || function() {}, fn = options.fn; + + if (isFunction(context)) { context = context.call(this); } + + if(context === true) { + return fn(this); + } else if(context === false || context == null) { + return inverse(this); + } else if (isArray(context)) { + if(context.length > 0) { + return instance.helpers.each(context, options); + } else { + return inverse(this); + } + } else { + return fn(context); + } + }); + + instance.registerHelper('each', function(context, options) { + var fn = options.fn, inverse = options.inverse; + var i = 0, ret = "", data; + + if (isFunction(context)) { context = context.call(this); } + + if (options.data) { + data = createFrame(options.data); + } + + if(context && typeof context === 'object') { + if (isArray(context)) { + for(var j = context.length; i 0) { + throw new Exception("Invalid path: " + original, this); + } else if (part === "..") { + depth++; + } else { + this.isScoped = true; + } + } else { + dig.push(part); + } + } + + this.original = original; + this.parts = dig; + this.string = dig.join('.'); + this.depth = depth; + + // an ID is simple if it only has one part, and that part is not + // `..` or `this`. + this.isSimple = parts.length === 1 && !this.isScoped && depth === 0; + + this.stringModeValue = this.string; + }, + + PartialNameNode: function(name, locInfo) { + LocationInfo.call(this, locInfo); + this.type = "PARTIAL_NAME"; + this.name = name.original; + }, + + DataNode: function(id, locInfo) { + LocationInfo.call(this, locInfo); + this.type = "DATA"; + this.id = id; + }, + + StringNode: function(string, locInfo) { + LocationInfo.call(this, locInfo); + this.type = "STRING"; + this.original = + this.string = + this.stringModeValue = string; + }, + + IntegerNode: function(integer, locInfo) { + LocationInfo.call(this, locInfo); + this.type = "INTEGER"; + this.original = + this.integer = integer; + this.stringModeValue = Number(integer); + }, + + BooleanNode: function(bool, locInfo) { + LocationInfo.call(this, locInfo); + this.type = "BOOLEAN"; + this.bool = bool; + this.stringModeValue = bool === "true"; + }, + + CommentNode: function(comment, locInfo) { + LocationInfo.call(this, locInfo); + this.type = "comment"; + this.comment = comment; + } + }; + + // Must be exported as an object rather than the root of the module as the jison lexer + // most modify the object to operate properly. + __exports__["default"] = AST; + }); +define("handlebars/compiler/base", + ["./parser","./ast","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var parser = __dependency1__["default"]; + var AST = __dependency2__["default"]; + + __exports__.parser = parser; + + function parse(input) { + // Just return if an already-compile AST was passed in. + if(input.constructor === AST.ProgramNode) { return input; } + + parser.yy = AST; + return parser.parse(input); + } + + __exports__.parse = parse; + }); +define("handlebars/compiler/compiler", + ["../exception","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Exception = __dependency1__["default"]; + + function Compiler() {} + + __exports__.Compiler = Compiler;// the foundHelper register will disambiguate helper lookup from finding a + // function in a context. This is necessary for mustache compatibility, which + // requires that context functions in blocks are evaluated by blockHelperMissing, + // and then proceed as if the resulting value was provided to blockHelperMissing. + + Compiler.prototype = { + compiler: Compiler, + + disassemble: function() { + var opcodes = this.opcodes, opcode, out = [], params, param; + + for (var i=0, l=opcodes.length; i 0) { + this.source[1] = this.source[1] + ", " + locals.join(", "); + } + + // Generate minimizer alias mappings + if (!this.isChild) { + for (var alias in this.context.aliases) { + if (this.context.aliases.hasOwnProperty(alias)) { + this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias]; + } + } + } + + if (this.source[1]) { + this.source[1] = "var " + this.source[1].substring(2) + ";"; + } + + // Merge children + if (!this.isChild) { + this.source[1] += '\n' + this.context.programs.join('\n') + '\n'; + } + + if (!this.environment.isSimple) { + this.pushSource("return buffer;"); + } + + var params = this.isChild ? ["depth0", "data"] : ["Handlebars", "depth0", "helpers", "partials", "data"]; + + for(var i=0, l=this.environment.depths.list.length; i this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); } + return this.topStackName(); + }, + topStackName: function() { + return "stack" + this.stackSlot; + }, + flushInline: function() { + var inlineStack = this.inlineStack; + if (inlineStack.length) { + this.inlineStack = []; + for (var i = 0, len = inlineStack.length; i < len; i++) { + var entry = inlineStack[i]; + if (entry instanceof Literal) { + this.compileStack.push(entry); + } else { + this.pushStack(entry); + } + } + } + }, + isInline: function() { + return this.inlineStack.length; + }, + + popStack: function(wrapped) { + var inline = this.isInline(), + item = (inline ? this.inlineStack : this.compileStack).pop(); + + if (!wrapped && (item instanceof Literal)) { + return item.value; + } else { + if (!inline) { + if (!this.stackSlot) { + throw new Exception('Invalid stack pop'); + } + this.stackSlot--; + } + return item; + } + }, + + topStack: function(wrapped) { + var stack = (this.isInline() ? this.inlineStack : this.compileStack), + item = stack[stack.length - 1]; + + if (!wrapped && (item instanceof Literal)) { + return item.value; + } else { + return item; + } + }, + + quotedString: function(str) { + return '"' + str + .replace(/\\/g, '\\\\') + .replace(/"/g, '\\"') + .replace(/\n/g, '\\n') + .replace(/\r/g, '\\r') + .replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4 + .replace(/\u2029/g, '\\u2029') + '"'; + }, + + setupHelper: function(paramSize, name, missingParams) { + var params = [], + paramsInit = this.setupParams(paramSize, params, missingParams); + var foundHelper = this.nameLookup('helpers', name, 'helper'); + + return { + params: params, + paramsInit: paramsInit, + name: foundHelper, + callParams: ["depth0"].concat(params).join(", "), + helperMissingParams: missingParams && ["depth0", this.quotedString(name)].concat(params).join(", ") + }; + }, + + setupOptions: function(paramSize, params) { + var options = [], contexts = [], types = [], param, inverse, program; + + options.push("hash:" + this.popStack()); + + if (this.options.stringParams) { + options.push("hashTypes:" + this.popStack()); + options.push("hashContexts:" + this.popStack()); + } + + inverse = this.popStack(); + program = this.popStack(); + + // Avoid setting fn and inverse if neither are set. This allows + // helpers to do a check for `if (options.fn)` + if (program || inverse) { + if (!program) { + this.context.aliases.self = "this"; + program = "self.noop"; + } + + if (!inverse) { + this.context.aliases.self = "this"; + inverse = "self.noop"; + } + + options.push("inverse:" + inverse); + options.push("fn:" + program); + } + + for(var i=0; i 2) { + expected.push("'" + this.terminals_[p] + "'"); + } + if (this.lexer.showPosition) { + errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'"; + } else { + errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1?"end of input":"'" + (this.terminals_[symbol] || symbol) + "'"); + } + this.parseError(errStr, {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected}); + } + } + if (action[0] instanceof Array && action.length > 1) { + throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol); + } + switch (action[0]) { + case 1: + stack.push(symbol); + vstack.push(this.lexer.yytext); + lstack.push(this.lexer.yylloc); + stack.push(action[1]); + symbol = null; + if (!preErrorSymbol) { + yyleng = this.lexer.yyleng; + yytext = this.lexer.yytext; + yylineno = this.lexer.yylineno; + yyloc = this.lexer.yylloc; + if (recovering > 0) + recovering--; + } else { + symbol = preErrorSymbol; + preErrorSymbol = null; + } + break; + case 2: + len = this.productions_[action[1]][1]; + yyval.$ = vstack[vstack.length - len]; + yyval._$ = {first_line: lstack[lstack.length - (len || 1)].first_line, last_line: lstack[lstack.length - 1].last_line, first_column: lstack[lstack.length - (len || 1)].first_column, last_column: lstack[lstack.length - 1].last_column}; + if (ranges) { + yyval._$.range = [lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1]]; + } + r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack); + if (typeof r !== "undefined") { + return r; + } + if (len) { + stack = stack.slice(0, -1 * len * 2); + vstack = vstack.slice(0, -1 * len); + lstack = lstack.slice(0, -1 * len); + } + stack.push(this.productions_[action[1]][0]); + vstack.push(yyval.$); + lstack.push(yyval._$); + newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; + stack.push(newState); + break; + case 3: + return true; + } + } + return true; + } + }; + + + function stripFlags(open, close) { + return { + left: open.charAt(2) === '~', + right: close.charAt(0) === '~' || close.charAt(1) === '~' + }; + } + + /* Jison generated lexer */ + var lexer = (function(){ + var lexer = ({EOF:1, + parseError:function parseError(str, hash) { + if (this.yy.parser) { + this.yy.parser.parseError(str, hash); + } else { + throw new Error(str); + } + }, + setInput:function (input) { + this._input = input; + this._more = this._less = this.done = false; + this.yylineno = this.yyleng = 0; + this.yytext = this.matched = this.match = ''; + this.conditionStack = ['INITIAL']; + this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0}; + if (this.options.ranges) this.yylloc.range = [0,0]; + this.offset = 0; + return this; + }, + input:function () { + var ch = this._input[0]; + this.yytext += ch; + this.yyleng++; + this.offset++; + this.match += ch; + this.matched += ch; + var lines = ch.match(/(?:\r\n?|\n).*/g); + if (lines) { + this.yylineno++; + this.yylloc.last_line++; + } else { + this.yylloc.last_column++; + } + if (this.options.ranges) this.yylloc.range[1]++; + + this._input = this._input.slice(1); + return ch; + }, + unput:function (ch) { + var len = ch.length; + var lines = ch.split(/(?:\r\n?|\n)/g); + + this._input = ch + this._input; + this.yytext = this.yytext.substr(0, this.yytext.length-len-1); + //this.yyleng -= len; + this.offset -= len; + var oldLines = this.match.split(/(?:\r\n?|\n)/g); + this.match = this.match.substr(0, this.match.length-1); + this.matched = this.matched.substr(0, this.matched.length-1); + + if (lines.length-1) this.yylineno -= lines.length-1; + var r = this.yylloc.range; + + this.yylloc = {first_line: this.yylloc.first_line, + last_line: this.yylineno+1, + first_column: this.yylloc.first_column, + last_column: lines ? + (lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length: + this.yylloc.first_column - len + }; + + if (this.options.ranges) { + this.yylloc.range = [r[0], r[0] + this.yyleng - len]; + } + return this; + }, + more:function () { + this._more = true; + return this; + }, + less:function (n) { + this.unput(this.match.slice(n)); + }, + pastInput:function () { + var past = this.matched.substr(0, this.matched.length - this.match.length); + return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, ""); + }, + upcomingInput:function () { + var next = this.match; + if (next.length < 20) { + next += this._input.substr(0, 20-next.length); + } + return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, ""); + }, + showPosition:function () { + var pre = this.pastInput(); + var c = new Array(pre.length + 1).join("-"); + return pre + this.upcomingInput() + "\n" + c+"^"; + }, + next:function () { + if (this.done) { + return this.EOF; + } + if (!this._input) this.done = true; + + var token, + match, + tempMatch, + index, + col, + lines; + if (!this._more) { + this.yytext = ''; + this.match = ''; + } + var rules = this._currentRules(); + for (var i=0;i < rules.length; i++) { + tempMatch = this._input.match(this.rules[rules[i]]); + if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { + match = tempMatch; + index = i; + if (!this.options.flex) break; + } + } + if (match) { + lines = match[0].match(/(?:\r\n?|\n).*/g); + if (lines) this.yylineno += lines.length; + this.yylloc = {first_line: this.yylloc.last_line, + last_line: this.yylineno+1, + first_column: this.yylloc.last_column, + last_column: lines ? lines[lines.length-1].length-lines[lines.length-1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length}; + this.yytext += match[0]; + this.match += match[0]; + this.matches = match; + this.yyleng = this.yytext.length; + if (this.options.ranges) { + this.yylloc.range = [this.offset, this.offset += this.yyleng]; + } + this._more = false; + this._input = this._input.slice(match[0].length); + this.matched += match[0]; + token = this.performAction.call(this, this.yy, this, rules[index],this.conditionStack[this.conditionStack.length-1]); + if (this.done && this._input) this.done = false; + if (token) return token; + else return; + } + if (this._input === "") { + return this.EOF; + } else { + return this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(), + {text: "", token: null, line: this.yylineno}); + } + }, + lex:function lex() { + var r = this.next(); + if (typeof r !== 'undefined') { + return r; + } else { + return this.lex(); + } + }, + begin:function begin(condition) { + this.conditionStack.push(condition); + }, + popState:function popState() { + return this.conditionStack.pop(); + }, + _currentRules:function _currentRules() { + return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules; + }, + topState:function () { + return this.conditionStack[this.conditionStack.length-2]; + }, + pushState:function begin(condition) { + this.begin(condition); + }}); + lexer.options = {}; + lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) { + + + function strip(start, end) { + return yy_.yytext = yy_.yytext.substr(start, yy_.yyleng-end); + } + + + var YYSTATE=YY_START + switch($avoiding_name_collisions) { + case 0: + if(yy_.yytext.slice(-2) === "\\\\") { + strip(0,1); + this.begin("mu"); + } else if(yy_.yytext.slice(-1) === "\\") { + strip(0,1); + this.begin("emu"); + } else { + this.begin("mu"); + } + if(yy_.yytext) return 14; + + break; + case 1:return 14; + break; + case 2: + this.popState(); + return 14; + + break; + case 3:strip(0,4); this.popState(); return 15; + break; + case 4:return 35; + break; + case 5:return 36; + break; + case 6:return 25; + break; + case 7:return 16; + break; + case 8:return 20; + break; + case 9:return 19; + break; + case 10:return 19; + break; + case 11:return 23; + break; + case 12:return 22; + break; + case 13:this.popState(); this.begin('com'); + break; + case 14:strip(3,5); this.popState(); return 15; + break; + case 15:return 22; + break; + case 16:return 41; + break; + case 17:return 40; + break; + case 18:return 40; + break; + case 19:return 44; + break; + case 20:// ignore whitespace + break; + case 21:this.popState(); return 24; + break; + case 22:this.popState(); return 18; + break; + case 23:yy_.yytext = strip(1,2).replace(/\\"/g,'"'); return 32; + break; + case 24:yy_.yytext = strip(1,2).replace(/\\'/g,"'"); return 32; + break; + case 25:return 42; + break; + case 26:return 34; + break; + case 27:return 34; + break; + case 28:return 33; + break; + case 29:return 40; + break; + case 30:yy_.yytext = strip(1,2); return 40; + break; + case 31:return 'INVALID'; + break; + case 32:return 5; + break; + } + }; + lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\()/,/^(?:\))/,/^(?:\{\{(~)?>)/,/^(?:\{\{(~)?#)/,/^(?:\{\{(~)?\/)/,/^(?:\{\{(~)?\^)/,/^(?:\{\{(~)?\s*else\b)/,/^(?:\{\{(~)?\{)/,/^(?:\{\{(~)?&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{(~)?)/,/^(?:=)/,/^(?:\.\.)/,/^(?:\.(?=([=~}\s\/.)])))/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}(~)?\}\})/,/^(?:(~)?\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@)/,/^(?:true(?=([~}\s)])))/,/^(?:false(?=([~}\s)])))/,/^(?:-?[0-9]+(?=([~}\s)])))/,/^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)]))))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:$)/]; + lexer.conditions = {"mu":{"rules":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"com":{"rules":[3],"inclusive":false},"INITIAL":{"rules":[0,1,32],"inclusive":true}}; + return lexer;})() + parser.lexer = lexer; + function Parser () { this.yy = {}; }Parser.prototype = parser;parser.Parser = Parser; + return new Parser; + })();__exports__["default"] = handlebars; + /* jshint ignore:end */ + }); +define("handlebars/compiler/printer", + ["./visitor","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Visitor = __dependency1__["default"]; + + function print(ast) { + return new PrintVisitor().accept(ast); + } + + __exports__.print = print;function PrintVisitor() { + this.padding = 0; + } + + __exports__.PrintVisitor = PrintVisitor;PrintVisitor.prototype = new Visitor(); + + PrintVisitor.prototype.pad = function(string, newline) { + var out = ""; + + for(var i=0,l=this.padding; i " + content + " }}"); + }; + + PrintVisitor.prototype.hash = function(hash) { + var pairs = hash.pairs; + var joinedPairs = [], left, right; + + for(var i=0, l=pairs.length; i 1) { + return "PATH:" + path; + } else { + return "ID:" + path; + } + }; + + PrintVisitor.prototype.PARTIAL_NAME = function(partialName) { + return "PARTIAL:" + partialName.name; + }; + + PrintVisitor.prototype.DATA = function(data) { + return "@" + this.accept(data.id); + }; + + PrintVisitor.prototype.content = function(content) { + return this.pad("CONTENT[ '" + content.string + "' ]"); + }; + + PrintVisitor.prototype.comment = function(comment) { + return this.pad("{{! '" + comment.comment + "' }}"); + }; + }); +define("handlebars/compiler/visitor", + ["exports"], + function(__exports__) { + "use strict"; + function Visitor() {} + + Visitor.prototype = { + constructor: Visitor, + + accept: function(object) { + return this[object.type](object); + } + }; + + __exports__["default"] = Visitor; + }); +define("handlebars/exception", + ["exports"], + function(__exports__) { + "use strict"; + + var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; + + function Exception(message, node) { + var line; + if (node && node.firstLine) { + line = node.firstLine; + + message += ' - ' + line + ':' + node.firstColumn; + } + + var tmp = Error.prototype.constructor.call(this, message); + + // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. + for (var idx = 0; idx < errorProps.length; idx++) { + this[errorProps[idx]] = tmp[errorProps[idx]]; + } + + if (line) { + this.lineNumber = line; + this.column = node.firstColumn; + } + } + + Exception.prototype = new Error(); + + __exports__["default"] = Exception; + }); +define("handlebars/runtime", + ["./utils","./exception","./base","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Utils = __dependency1__; + var Exception = __dependency2__["default"]; + var COMPILER_REVISION = __dependency3__.COMPILER_REVISION; + var REVISION_CHANGES = __dependency3__.REVISION_CHANGES; + + function checkRevision(compilerInfo) { + var compilerRevision = compilerInfo && compilerInfo[0] || 1, + currentRevision = COMPILER_REVISION; + + if (compilerRevision !== currentRevision) { + if (compilerRevision < currentRevision) { + var runtimeVersions = REVISION_CHANGES[currentRevision], + compilerVersions = REVISION_CHANGES[compilerRevision]; + throw new Exception("Template was precompiled with an older version of Handlebars than the current runtime. "+ + "Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+")."); + } else { + // Use the embedded version info since the runtime doesn't know about this revision yet + throw new Exception("Template was precompiled with a newer version of Handlebars than the current runtime. "+ + "Please update your runtime to a newer version ("+compilerInfo[1]+")."); + } + } + } + + __exports__.checkRevision = checkRevision;// TODO: Remove this line and break up compilePartial + + function template(templateSpec, env) { + if (!env) { + throw new Exception("No environment passed to template"); + } + + // Note: Using env.VM references rather than local var references throughout this section to allow + // for external users to override these as psuedo-supported APIs. + var invokePartialWrapper = function(partial, name, context, helpers, partials, data) { + var result = env.VM.invokePartial.apply(this, arguments); + if (result != null) { return result; } + + if (env.compile) { + var options = { helpers: helpers, partials: partials, data: data }; + partials[name] = env.compile(partial, { data: data !== undefined }, env); + return partials[name](context, options); + } else { + throw new Exception("The partial " + name + " could not be compiled when running in runtime-only mode"); + } + }; + + // Just add water + var container = { + escapeExpression: Utils.escapeExpression, + invokePartial: invokePartialWrapper, + programs: [], + program: function(i, fn, data) { + var programWrapper = this.programs[i]; + if(data) { + programWrapper = program(i, fn, data); + } else if (!programWrapper) { + programWrapper = this.programs[i] = program(i, fn); + } + return programWrapper; + }, + merge: function(param, common) { + var ret = param || common; + + if (param && common && (param !== common)) { + ret = {}; + Utils.extend(ret, common); + Utils.extend(ret, param); + } + return ret; + }, + programWithDepth: env.VM.programWithDepth, + noop: env.VM.noop, + compilerInfo: null + }; + + return function(context, options) { + options = options || {}; + var namespace = options.partial ? options : env, + helpers, + partials; + + if (!options.partial) { + helpers = options.helpers; + partials = options.partials; + } + var result = templateSpec.call( + container, + namespace, context, + helpers, + partials, + options.data); + + if (!options.partial) { + env.VM.checkRevision(container.compilerInfo); + } + + return result; + }; + } + + __exports__.template = template;function programWithDepth(i, fn, data /*, $depth */) { + var args = Array.prototype.slice.call(arguments, 3); + + var prog = function(context, options) { + options = options || {}; + + return fn.apply(this, [context, options.data || data].concat(args)); + }; + prog.program = i; + prog.depth = args.length; + return prog; + } + + __exports__.programWithDepth = programWithDepth;function program(i, fn, data) { + var prog = function(context, options) { + options = options || {}; + + return fn(context, options.data || data); + }; + prog.program = i; + prog.depth = 0; + return prog; + } + + __exports__.program = program;function invokePartial(partial, name, context, helpers, partials, data) { + var options = { partial: true, helpers: helpers, partials: partials, data: data }; + + if(partial === undefined) { + throw new Exception("The partial " + name + " could not be found"); + } else if(partial instanceof Function) { + return partial(context, options); + } + } + + __exports__.invokePartial = invokePartial;function noop() { return ""; } + + __exports__.noop = noop; + }); +define("handlebars/safe-string", + ["exports"], + function(__exports__) { + "use strict"; + // Build out our basic SafeString type + function SafeString(string) { + this.string = string; + } + + SafeString.prototype.toString = function() { + return "" + this.string; + }; + + __exports__["default"] = SafeString; + }); +define("handlebars/utils", + ["./safe-string","exports"], + function(__dependency1__, __exports__) { + "use strict"; + /*jshint -W004 */ + var SafeString = __dependency1__["default"]; + + var escape = { + "&": "&", + "<": "<", + ">": ">", + '"': """, + "'": "'", + "`": "`" + }; + + var badChars = /[&<>"'`]/g; + var possible = /[&<>"'`]/; + + function escapeChar(chr) { + return escape[chr] || "&"; + } + + function extend(obj, value) { + for(var key in value) { + if(Object.prototype.hasOwnProperty.call(value, key)) { + obj[key] = value[key]; + } + } + } + + __exports__.extend = extend;var toString = Object.prototype.toString; + __exports__.toString = toString; + // Sourced from lodash + // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt + var isFunction = function(value) { + return typeof value === 'function'; + }; + // fallback for older versions of Chrome and Safari + if (isFunction(/x/)) { + isFunction = function(value) { + return typeof value === 'function' && toString.call(value) === '[object Function]'; + }; + } + var isFunction; + __exports__.isFunction = isFunction; + var isArray = Array.isArray || function(value) { + return (value && typeof value === 'object') ? toString.call(value) === '[object Array]' : false; + }; + __exports__.isArray = isArray; + + function escapeExpression(string) { + // don't escape SafeStrings, since they're already safe + if (string instanceof SafeString) { + return string.toString(); + } else if (!string && string !== 0) { + return ""; + } + + // Force a string conversion as this will be done by the append regardless and + // the regex test will do this transparently behind the scenes, causing issues if + // an object's to string has escaped characters in it. + string = "" + string; + + if(!possible.test(string)) { return string; } + return string.replace(badChars, escapeChar); + } + + __exports__.escapeExpression = escapeExpression;function isEmpty(value) { + if (!value && value !== 0) { + return true; + } else if (isArray(value) && value.length === 0) { + return true; + } else { + return false; + } + } + + __exports__.isEmpty = isEmpty; + }); +define("htmlbars-runtime", + ["htmlbars-runtime/hooks","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var hooks = __dependency1__; + + var hooks; + __exports__.hooks = hooks; + }); +define("htmlbars-runtime/hooks", + ["./utils","../handlebars/safe-string","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var merge = __dependency1__.merge; + var SafeString = __dependency2__["default"]; + + function content(morph, helperName, context, params, options, env) { + var value, helper = this.lookupHelper(helperName, context, options); + if (helper) { + value = helper(params, options, env); + } else { + value = this.simple(context, helperName, options); + } + if (!options.escaped) { + value = new SafeString(value); + } + morph.update(value); + } + + __exports__.content = content;function webComponent(morph, tagName, context, options, env) { + var value, helper = this.lookupHelper(tagName, context, options); + if (helper) { + value = helper(null, options, env); + } else { + value = this.webComponentFallback(morph, tagName, context, options, env); + } + morph.update(value); + } + + __exports__.webComponent = webComponent;function webComponentFallback(morph, tagName, context, options, env) { + var element = env.dom.createElement(tagName); + var hash = options.hash, hashTypes = options.hashTypes; + + for (var name in hash) { + if (hashTypes[name] === 'id') { + element.setAttribute(name, this.simple(context, hash[name], options)); + } else { + element.setAttribute(name, hash[name]); + } + } + element.appendChild(options.render(context, env, morph.contextualElement)); + return element; + } + + __exports__.webComponentFallback = webComponentFallback;function element(domElement, helperName, context, params, options, env) { + var helper = this.lookupHelper(helperName, context, options); + if (helper) { + helper(params, options, env); + } + } + + __exports__.element = element;function attribute(params, options, env) { + var attrName = params[0]; + var attrValue = params[1]; + + if (attrValue === null) { + options.element.removeAttribute(attrName); + } else { + options.element.setAttribute(attrName, attrValue); + } + } + + __exports__.attribute = attribute;function concat(params, options, env) { + var context = options.context; + var value = ""; + for (var i = 0, l = params.length; i < l; i++) { + if (options.types[i] === 'id') { + value += this.simple(context, params[i], options); + } else { + value += params[i]; + } + } + return value; + } + + __exports__.concat = concat;function partial(params, options, env) { + return env.partials[params[0]](options.context, env); + } + + __exports__.partial = partial;function subexpr(helperName, context, params, options, env) { + var helper = this.lookupHelper(helperName, context, options); + if (helper) { + return helper(params, options, env); + } else { + return this.simple(context, helperName, options); + } + } + + __exports__.subexpr = subexpr;function lookupHelper(helperName, context, options) { + if (helperName === 'attribute') { + return this.attribute; + } + else if (helperName === 'partial'){ + return this.partial; + } + else if (helperName === 'concat') { + return this.concat; + } + } + + __exports__.lookupHelper = lookupHelper;function simple(context, name, options) { + return context[name]; + } + + __exports__.simple = simple;function hydrationHooks(extensions) { + var base = { + content: content, + webComponent: webComponent, + webComponentFallback: webComponentFallback, + element: element, + attribute: attribute, + concat: concat, + subexpr: subexpr, + lookupHelper: lookupHelper, + simple: simple, + partial: partial + }; + + return extensions ? merge(extensions, base) : base; + } + + __exports__.hydrationHooks = hydrationHooks; + }); +define("htmlbars-runtime/utils", + ["exports"], + function(__exports__) { + "use strict"; + function merge(options, defaults) { + for (var prop in defaults) { + if (options.hasOwnProperty(prop)) { continue; } + options[prop] = defaults[prop]; + } + return options; + } + + __exports__.merge = merge; + }); +define("morph", + ["./morph/morph","./morph/dom-helper","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Morph = __dependency1__["default"]; + var Morph; + __exports__.Morph = Morph; + var DOMHelper = __dependency2__["default"]; + var DOMHelper; + __exports__.DOMHelper = DOMHelper; + }); +define("morph/dom-helper", + ["../morph/morph","./dom-helper/build-html-dom","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Morph = __dependency1__["default"]; + var buildHTMLDOM = __dependency2__.buildHTMLDOM; + var svgNamespace = __dependency2__.svgNamespace; + var svgHTMLIntegrationPoints = __dependency2__.svgHTMLIntegrationPoints; + + var deletesBlankTextNodes = (function(){ + var element = document.createElement('div'); + element.appendChild( document.createTextNode('') ); + var clonedElement = element.cloneNode(true); + return clonedElement.childNodes.length === 0; + })(); + + var ignoresCheckedAttribute = (function(){ + var element = document.createElement('input'); + element.setAttribute('checked', 'checked'); + var clonedElement = element.cloneNode(false); + return !clonedElement.checked; + })(); + + function isSVG(ns){ + return ns === svgNamespace; + } + + // This is not the namespace of the element, but of + // the elements inside that elements. + function interiorNamespace(element){ + if ( + element && + element.namespaceURI === svgNamespace && + !svgHTMLIntegrationPoints[element.tagName] + ) { + return svgNamespace; + } else { + return null; + } + } + + // The HTML spec allows for "omitted start tags". These tags are optional + // when their intended child is the first thing in the parent tag. For + // example, this is a tbody start tag: + // + //
+ // + // + // + // The tbody may be omitted, and the browser will accept and render: + // + //
+ // + // + // However, the omitted start tag will still be added to the DOM. Here + // we test the string and context to see if the browser is about to + // perform this cleanup. + // + // http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#optional-tags + // describes which tags are omittable. The spec for tbody and colgroup + // explains this behavior: + // + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-tbody-element + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-colgroup-element + // + + var omittedStartTagChildTest = /<([\w:]+)/; + function detectOmittedStartTag(string, contextualElement){ + // Omitted start tags are only inside table tags. + if (contextualElement.tagName === 'TABLE') { + var omittedStartTagChildMatch = omittedStartTagChildTest.exec(string); + if (omittedStartTagChildMatch) { + var omittedStartTagChild = omittedStartTagChildMatch[1]; + // It is already asserted that the contextual element is a table + // and not the proper start tag. Just see if a tag was omitted. + return omittedStartTagChild === 'tr' || + omittedStartTagChild === 'col'; + } + } + } + + function buildSVGDOM(html, dom){ + var div = dom.document.createElement('div'); + div.innerHTML = ''+html+''; + return div.firstChild.childNodes; + } + + /* + * A class wrapping DOM functions to address environment compatibility, + * namespaces, contextual elements for morph un-escaped content + * insertion. + * + * When entering a template, a DOMHelper should be passed: + * + * template(context, { hooks: hooks, dom: new DOMHelper() }); + * + * TODO: support foreignObject as a passed contextual element. It has + * a namespace (svg) that does not match its internal namespace + * (xhtml). + * + * @class DOMHelper + * @constructor + * @param {HTMLDocument} _document The document DOM methods are proxied to + */ + function DOMHelper(_document){ + this.document = _document || window.document; + this.namespace = null; + } + + var prototype = DOMHelper.prototype; + prototype.constructor = DOMHelper; + + prototype.insertBefore = function(element, childElement, referenceChild) { + return element.insertBefore(childElement, referenceChild); + }; + + prototype.appendChild = function(element, childElement) { + return element.appendChild(childElement); + }; + + prototype.appendText = function(element, text) { + return element.appendChild(this.document.createTextNode(text)); + }; + + prototype.setAttribute = function(element, name, value) { + element.setAttribute(name, value); + }; + + if (document.createElementNS) { + // Only opt into namespace detection if a contextualElement + // is passed. + prototype.createElement = function(tagName, contextualElement) { + var namespace = this.namespace; + if (contextualElement) { + if (tagName === 'svg') { + namespace = svgNamespace; + } else { + namespace = interiorNamespace(contextualElement); + } + } + if (namespace) { + return this.document.createElementNS(namespace, tagName); + } else { + return this.document.createElement(tagName); + } + }; + } else { + prototype.createElement = function(tagName) { + return this.document.createElement(tagName); + }; + } + + prototype.setNamespace = function(ns) { + this.namespace = ns; + }; + + prototype.detectNamespace = function(element) { + this.namespace = interiorNamespace(element); + }; + + prototype.createDocumentFragment = function(){ + return this.document.createDocumentFragment(); + }; + + prototype.createTextNode = function(text){ + return this.document.createTextNode(text); + }; + + prototype.repairClonedNode = function(element, blankChildTextNodes, isChecked){ + if (deletesBlankTextNodes && blankChildTextNodes.length > 0) { + for (var i=0, len=blankChildTextNodes.length;i]*)>", 'i'))[0]; + var endTag = ''; + + var wrappedHTML = [startTag, html, endTag]; + + var i = wrappingTags.length; + var wrappedDepth = 1 + i; + while(i--) { + wrappedHTML.unshift('<'+wrappingTags[i]+'>'); + wrappedHTML.push(''); + } + + var wrapper = document.createElement('div'); + scriptSafeInnerHTML(wrapper, wrappedHTML.join('')); + var element = wrapper; + while (wrappedDepth--) { + element = element.firstChild; + while (element && element.nodeType !== 1) { + element = element.nextSibling; + } + } + while (element && element.tagName !== tagName) { + element = element.nextSibling; + } + return element ? element.childNodes : []; + } + + var buildDOM; + if (needsShy) { + buildDOM = function buildDOM(html, contextualElement, dom){ + contextualElement = dom.cloneNode(contextualElement, false); + scriptSafeInnerHTML(contextualElement, html); + return contextualElement.childNodes; + }; + } else { + buildDOM = function buildDOM(html, contextualElement, dom){ + contextualElement = dom.cloneNode(contextualElement, false); + contextualElement.innerHTML = html; + return contextualElement.childNodes; + }; + } + + + var buildIESafeDOM; + if (tagNamesRequiringInnerHTMLFix.length > 0 || movesWhitespace) { + buildIESafeDOM = function buildIESafeDOM(html, contextualElement, dom) { + // Make a list of the leading text on script nodes. Include + // script tags without any whitespace for easier processing later. + var spacesBefore = []; + var spacesAfter = []; + html = html.replace(/(\s*)()(\s*)/g, function(match, tag, spaces) { + spacesAfter.push(spaces); + return tag; + }); + + // Fetch nodes + var nodes; + if (tagNamesRequiringInnerHTMLFix[contextualElement.tagName.toLowerCase()]) { + // buildDOMWithFix uses string wrappers for problematic innerHTML. + nodes = buildDOMWithFix(html, contextualElement); + } else { + nodes = buildDOM(html, contextualElement, dom); + } + + // Build a list of script tags, the nodes themselves will be + // mutated as we add test nodes. + var i, j, node, nodeScriptNodes; + var scriptNodes = []; + for (i=0;node=nodes[i];i++) { + if (node.nodeType !== 1) { + continue; + } + if (node.tagName === 'SCRIPT') { + scriptNodes.push(node); + } else { + nodeScriptNodes = node.getElementsByTagName('script'); + for (j=0;j 0) { + textNode = dom.document.createTextNode(spaceBefore); + scriptNode.parentNode.insertBefore(textNode, scriptNode); + } + + spaceAfter = spacesAfter[i]; + if (spaceAfter && spaceAfter.length > 0) { + textNode = dom.document.createTextNode(spaceAfter); + scriptNode.parentNode.insertBefore(textNode, scriptNode.nextSibling); + } + } + + return nodes; + }; + } else { + buildIESafeDOM = buildDOM; + } + + var buildHTMLDOM; + if (needsIntegrationPointFix) { + buildHTMLDOM = function buildHTMLDOM(html, contextualElement, dom){ + if (svgHTMLIntegrationPoints[contextualElement.tagName]) { + return buildIESafeDOM(html, document.createElement('div'), dom); + } else { + return buildIESafeDOM(html, contextualElement, dom); + } + }; + } else { + buildHTMLDOM = buildIESafeDOM; + } + + __exports__.buildHTMLDOM = buildHTMLDOM; + }); +define("morph/morph", + ["exports"], + function(__exports__) { + "use strict"; + var splice = Array.prototype.splice; + + function ensureStartEnd(start, end) { + if (start === null || end === null) { + throw new Error('a fragment parent must have boundary nodes in order to detect insertion'); + } + } + + function ensureContext(contextualElement) { + if (!contextualElement || contextualElement.nodeType !== 1) { + throw new Error('An element node must be provided for a contextualElement, you provided ' + + (contextualElement ? 'nodeType ' + contextualElement.nodeType : 'nothing')); + } + } + + // TODO: this is an internal API, this should be an assert + function Morph(parent, start, end, domHelper, contextualElement) { + if (parent.nodeType === 11) { + ensureStartEnd(start, end); + this.element = null; + } else { + this.element = parent; + } + this._parent = parent; + this.start = start; + this.end = end; + this.domHelper = domHelper; + ensureContext(contextualElement); + this.contextualElement = contextualElement; + this.reset(); + } + + Morph.prototype.reset = function() { + this.text = null; + this.owner = null; + this.morphs = null; + this.before = null; + this.after = null; + this.escaped = true; + }; + + Morph.prototype.parent = function () { + if (!this.element) { + var parent = this.start.parentNode; + if (this._parent !== parent) { + this.element = this._parent = parent; + } + } + return this._parent; + }; + + Morph.prototype.destroy = function () { + if (this.owner) { + this.owner.removeMorph(this); + } else { + clear(this.element || this.parent(), this.start, this.end); + } + }; + + Morph.prototype.removeMorph = function (morph) { + var morphs = this.morphs; + for (var i=0, l=morphs.length; i 0 ? morphs[index-1] : null; + var after = index < morphs.length ? morphs[index] : null; + var start = before === null ? this.start : (before.end === null ? parent.lastChild : before.end.previousSibling); + var end = after === null ? this.end : (after.start === null ? parent.firstChild : after.start.nextSibling); + var morph = new Morph(parent, start, end, this.domHelper, this.contextualElement); + + morph.owner = this; + morph._update(parent, node); + + if (before !== null) { + morph.before = before; + before.end = start.nextSibling; + before.after = morph; + } + + if (after !== null) { + morph.after = after; + after.before = morph; + after.start = end.previousSibling; + } + + this.morphs.splice(index, 0, morph); + return morph; + }; + + Morph.prototype.replace = function (index, removedLength, addedNodes) { + if (this.morphs === null) this.morphs = []; + var parent = this.element || this.parent(); + var morphs = this.morphs; + var before = index > 0 ? morphs[index-1] : null; + var after = index+removedLength < morphs.length ? morphs[index+removedLength] : null; + var start = before === null ? this.start : (before.end === null ? parent.lastChild : before.end.previousSibling); + var end = after === null ? this.end : (after.start === null ? parent.firstChild : after.start.nextSibling); + var addedLength = addedNodes === undefined ? 0 : addedNodes.length; + var args, i, current; + + if (removedLength > 0) { + clear(parent, start, end); + } + + if (addedLength === 0) { + if (before !== null) { + before.after = after; + before.end = end; + } + if (after !== null) { + after.before = before; + after.start = start; + } + morphs.splice(index, removedLength); + return; + } + + args = new Array(addedLength+2); + if (addedLength > 0) { + for (i=0; i= 1.0.0' + }; + __exports__.REVISION_CHANGES = REVISION_CHANGES; + var isArray = Utils.isArray, + isFunction = Utils.isFunction, + toString = Utils.toString, + objectType = '[object Object]'; + + function HandlebarsEnvironment(helpers, partials) { + this.helpers = helpers || {}; + this.partials = partials || {}; + + registerDefaultHelpers(this); + } + + __exports__.HandlebarsEnvironment = HandlebarsEnvironment;HandlebarsEnvironment.prototype = { + constructor: HandlebarsEnvironment, + + logger: logger, + log: log, + + registerHelper: function(name, fn, inverse) { + if (toString.call(name) === objectType) { + if (inverse || fn) { throw new Exception('Arg not supported with multiple helpers'); } + Utils.extend(this.helpers, name); + } else { + if (inverse) { fn.not = inverse; } + this.helpers[name] = fn; + } + }, + + registerPartial: function(name, str) { + if (toString.call(name) === objectType) { + Utils.extend(this.partials, name); + } else { + this.partials[name] = str; + } + } + }; + + function registerDefaultHelpers(instance) { + instance.registerHelper('helperMissing', function(arg) { + if(arguments.length === 2) { + return undefined; + } else { + throw new Exception("Missing helper: '" + arg + "'"); + } + }); + + instance.registerHelper('blockHelperMissing', function(context, options) { + var inverse = options.inverse || function() {}, fn = options.fn; + + if (isFunction(context)) { context = context.call(this); } + + if(context === true) { + return fn(this); + } else if(context === false || context == null) { + return inverse(this); + } else if (isArray(context)) { + if(context.length > 0) { + return instance.helpers.each(context, options); + } else { + return inverse(this); + } + } else { + return fn(context); + } + }); + + instance.registerHelper('each', function(context, options) { + var fn = options.fn, inverse = options.inverse; + var i = 0, ret = "", data; + + if (isFunction(context)) { context = context.call(this); } + + if (options.data) { + data = createFrame(options.data); + } + + if(context && typeof context === 'object') { + if (isArray(context)) { + for(var j = context.length; i 0) { + throw new Exception("Invalid path: " + original, this); + } else if (part === "..") { + depth++; + } else { + this.isScoped = true; + } + } else { + dig.push(part); + } + } + + this.original = original; + this.parts = dig; + this.string = dig.join('.'); + this.depth = depth; + + // an ID is simple if it only has one part, and that part is not + // `..` or `this`. + this.isSimple = parts.length === 1 && !this.isScoped && depth === 0; + + this.stringModeValue = this.string; + }, + + PartialNameNode: function(name, locInfo) { + LocationInfo.call(this, locInfo); + this.type = "PARTIAL_NAME"; + this.name = name.original; + }, + + DataNode: function(id, locInfo) { + LocationInfo.call(this, locInfo); + this.type = "DATA"; + this.id = id; + }, + + StringNode: function(string, locInfo) { + LocationInfo.call(this, locInfo); + this.type = "STRING"; + this.original = + this.string = + this.stringModeValue = string; + }, + + IntegerNode: function(integer, locInfo) { + LocationInfo.call(this, locInfo); + this.type = "INTEGER"; + this.original = + this.integer = integer; + this.stringModeValue = Number(integer); + }, + + BooleanNode: function(bool, locInfo) { + LocationInfo.call(this, locInfo); + this.type = "BOOLEAN"; + this.bool = bool; + this.stringModeValue = bool === "true"; + }, + + CommentNode: function(comment, locInfo) { + LocationInfo.call(this, locInfo); + this.type = "comment"; + this.comment = comment; + } + }; + + // Must be exported as an object rather than the root of the module as the jison lexer + // most modify the object to operate properly. + __exports__["default"] = AST; + }); +define("handlebars/compiler/base", + ["./parser","./ast","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var parser = __dependency1__["default"]; + var AST = __dependency2__["default"]; + + __exports__.parser = parser; + + function parse(input) { + // Just return if an already-compile AST was passed in. + if(input.constructor === AST.ProgramNode) { return input; } + + parser.yy = AST; + return parser.parse(input); + } + + __exports__.parse = parse; + }); +define("handlebars/compiler/compiler", + ["../exception","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Exception = __dependency1__["default"]; + + function Compiler() {} + + __exports__.Compiler = Compiler;// the foundHelper register will disambiguate helper lookup from finding a + // function in a context. This is necessary for mustache compatibility, which + // requires that context functions in blocks are evaluated by blockHelperMissing, + // and then proceed as if the resulting value was provided to blockHelperMissing. + + Compiler.prototype = { + compiler: Compiler, + + disassemble: function() { + var opcodes = this.opcodes, opcode, out = [], params, param; + + for (var i=0, l=opcodes.length; i 0) { + this.source[1] = this.source[1] + ", " + locals.join(", "); + } + + // Generate minimizer alias mappings + if (!this.isChild) { + for (var alias in this.context.aliases) { + if (this.context.aliases.hasOwnProperty(alias)) { + this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias]; + } + } + } + + if (this.source[1]) { + this.source[1] = "var " + this.source[1].substring(2) + ";"; + } + + // Merge children + if (!this.isChild) { + this.source[1] += '\n' + this.context.programs.join('\n') + '\n'; + } + + if (!this.environment.isSimple) { + this.pushSource("return buffer;"); + } + + var params = this.isChild ? ["depth0", "data"] : ["Handlebars", "depth0", "helpers", "partials", "data"]; + + for(var i=0, l=this.environment.depths.list.length; i this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); } + return this.topStackName(); + }, + topStackName: function() { + return "stack" + this.stackSlot; + }, + flushInline: function() { + var inlineStack = this.inlineStack; + if (inlineStack.length) { + this.inlineStack = []; + for (var i = 0, len = inlineStack.length; i < len; i++) { + var entry = inlineStack[i]; + if (entry instanceof Literal) { + this.compileStack.push(entry); + } else { + this.pushStack(entry); + } + } + } + }, + isInline: function() { + return this.inlineStack.length; + }, + + popStack: function(wrapped) { + var inline = this.isInline(), + item = (inline ? this.inlineStack : this.compileStack).pop(); + + if (!wrapped && (item instanceof Literal)) { + return item.value; + } else { + if (!inline) { + if (!this.stackSlot) { + throw new Exception('Invalid stack pop'); + } + this.stackSlot--; + } + return item; + } + }, + + topStack: function(wrapped) { + var stack = (this.isInline() ? this.inlineStack : this.compileStack), + item = stack[stack.length - 1]; + + if (!wrapped && (item instanceof Literal)) { + return item.value; + } else { + return item; + } + }, + + quotedString: function(str) { + return '"' + str + .replace(/\\/g, '\\\\') + .replace(/"/g, '\\"') + .replace(/\n/g, '\\n') + .replace(/\r/g, '\\r') + .replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4 + .replace(/\u2029/g, '\\u2029') + '"'; + }, + + setupHelper: function(paramSize, name, missingParams) { + var params = [], + paramsInit = this.setupParams(paramSize, params, missingParams); + var foundHelper = this.nameLookup('helpers', name, 'helper'); + + return { + params: params, + paramsInit: paramsInit, + name: foundHelper, + callParams: ["depth0"].concat(params).join(", "), + helperMissingParams: missingParams && ["depth0", this.quotedString(name)].concat(params).join(", ") + }; + }, + + setupOptions: function(paramSize, params) { + var options = [], contexts = [], types = [], param, inverse, program; + + options.push("hash:" + this.popStack()); + + if (this.options.stringParams) { + options.push("hashTypes:" + this.popStack()); + options.push("hashContexts:" + this.popStack()); + } + + inverse = this.popStack(); + program = this.popStack(); + + // Avoid setting fn and inverse if neither are set. This allows + // helpers to do a check for `if (options.fn)` + if (program || inverse) { + if (!program) { + this.context.aliases.self = "this"; + program = "self.noop"; + } + + if (!inverse) { + this.context.aliases.self = "this"; + inverse = "self.noop"; + } + + options.push("inverse:" + inverse); + options.push("fn:" + program); + } + + for(var i=0; i 2) { + expected.push("'" + this.terminals_[p] + "'"); + } + if (this.lexer.showPosition) { + errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'"; + } else { + errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1?"end of input":"'" + (this.terminals_[symbol] || symbol) + "'"); + } + this.parseError(errStr, {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected}); + } + } + if (action[0] instanceof Array && action.length > 1) { + throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol); + } + switch (action[0]) { + case 1: + stack.push(symbol); + vstack.push(this.lexer.yytext); + lstack.push(this.lexer.yylloc); + stack.push(action[1]); + symbol = null; + if (!preErrorSymbol) { + yyleng = this.lexer.yyleng; + yytext = this.lexer.yytext; + yylineno = this.lexer.yylineno; + yyloc = this.lexer.yylloc; + if (recovering > 0) + recovering--; + } else { + symbol = preErrorSymbol; + preErrorSymbol = null; + } + break; + case 2: + len = this.productions_[action[1]][1]; + yyval.$ = vstack[vstack.length - len]; + yyval._$ = {first_line: lstack[lstack.length - (len || 1)].first_line, last_line: lstack[lstack.length - 1].last_line, first_column: lstack[lstack.length - (len || 1)].first_column, last_column: lstack[lstack.length - 1].last_column}; + if (ranges) { + yyval._$.range = [lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1]]; + } + r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack); + if (typeof r !== "undefined") { + return r; + } + if (len) { + stack = stack.slice(0, -1 * len * 2); + vstack = vstack.slice(0, -1 * len); + lstack = lstack.slice(0, -1 * len); + } + stack.push(this.productions_[action[1]][0]); + vstack.push(yyval.$); + lstack.push(yyval._$); + newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; + stack.push(newState); + break; + case 3: + return true; + } + } + return true; + } + }; + + + function stripFlags(open, close) { + return { + left: open.charAt(2) === '~', + right: close.charAt(0) === '~' || close.charAt(1) === '~' + }; + } + + /* Jison generated lexer */ + var lexer = (function(){ + var lexer = ({EOF:1, + parseError:function parseError(str, hash) { + if (this.yy.parser) { + this.yy.parser.parseError(str, hash); + } else { + throw new Error(str); + } + }, + setInput:function (input) { + this._input = input; + this._more = this._less = this.done = false; + this.yylineno = this.yyleng = 0; + this.yytext = this.matched = this.match = ''; + this.conditionStack = ['INITIAL']; + this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0}; + if (this.options.ranges) this.yylloc.range = [0,0]; + this.offset = 0; + return this; + }, + input:function () { + var ch = this._input[0]; + this.yytext += ch; + this.yyleng++; + this.offset++; + this.match += ch; + this.matched += ch; + var lines = ch.match(/(?:\r\n?|\n).*/g); + if (lines) { + this.yylineno++; + this.yylloc.last_line++; + } else { + this.yylloc.last_column++; + } + if (this.options.ranges) this.yylloc.range[1]++; + + this._input = this._input.slice(1); + return ch; + }, + unput:function (ch) { + var len = ch.length; + var lines = ch.split(/(?:\r\n?|\n)/g); + + this._input = ch + this._input; + this.yytext = this.yytext.substr(0, this.yytext.length-len-1); + //this.yyleng -= len; + this.offset -= len; + var oldLines = this.match.split(/(?:\r\n?|\n)/g); + this.match = this.match.substr(0, this.match.length-1); + this.matched = this.matched.substr(0, this.matched.length-1); + + if (lines.length-1) this.yylineno -= lines.length-1; + var r = this.yylloc.range; + + this.yylloc = {first_line: this.yylloc.first_line, + last_line: this.yylineno+1, + first_column: this.yylloc.first_column, + last_column: lines ? + (lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length: + this.yylloc.first_column - len + }; + + if (this.options.ranges) { + this.yylloc.range = [r[0], r[0] + this.yyleng - len]; + } + return this; + }, + more:function () { + this._more = true; + return this; + }, + less:function (n) { + this.unput(this.match.slice(n)); + }, + pastInput:function () { + var past = this.matched.substr(0, this.matched.length - this.match.length); + return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, ""); + }, + upcomingInput:function () { + var next = this.match; + if (next.length < 20) { + next += this._input.substr(0, 20-next.length); + } + return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, ""); + }, + showPosition:function () { + var pre = this.pastInput(); + var c = new Array(pre.length + 1).join("-"); + return pre + this.upcomingInput() + "\n" + c+"^"; + }, + next:function () { + if (this.done) { + return this.EOF; + } + if (!this._input) this.done = true; + + var token, + match, + tempMatch, + index, + col, + lines; + if (!this._more) { + this.yytext = ''; + this.match = ''; + } + var rules = this._currentRules(); + for (var i=0;i < rules.length; i++) { + tempMatch = this._input.match(this.rules[rules[i]]); + if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { + match = tempMatch; + index = i; + if (!this.options.flex) break; + } + } + if (match) { + lines = match[0].match(/(?:\r\n?|\n).*/g); + if (lines) this.yylineno += lines.length; + this.yylloc = {first_line: this.yylloc.last_line, + last_line: this.yylineno+1, + first_column: this.yylloc.last_column, + last_column: lines ? lines[lines.length-1].length-lines[lines.length-1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length}; + this.yytext += match[0]; + this.match += match[0]; + this.matches = match; + this.yyleng = this.yytext.length; + if (this.options.ranges) { + this.yylloc.range = [this.offset, this.offset += this.yyleng]; + } + this._more = false; + this._input = this._input.slice(match[0].length); + this.matched += match[0]; + token = this.performAction.call(this, this.yy, this, rules[index],this.conditionStack[this.conditionStack.length-1]); + if (this.done && this._input) this.done = false; + if (token) return token; + else return; + } + if (this._input === "") { + return this.EOF; + } else { + return this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(), + {text: "", token: null, line: this.yylineno}); + } + }, + lex:function lex() { + var r = this.next(); + if (typeof r !== 'undefined') { + return r; + } else { + return this.lex(); + } + }, + begin:function begin(condition) { + this.conditionStack.push(condition); + }, + popState:function popState() { + return this.conditionStack.pop(); + }, + _currentRules:function _currentRules() { + return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules; + }, + topState:function () { + return this.conditionStack[this.conditionStack.length-2]; + }, + pushState:function begin(condition) { + this.begin(condition); + }}); + lexer.options = {}; + lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) { + + + function strip(start, end) { + return yy_.yytext = yy_.yytext.substr(start, yy_.yyleng-end); + } + + + var YYSTATE=YY_START + switch($avoiding_name_collisions) { + case 0: + if(yy_.yytext.slice(-2) === "\\\\") { + strip(0,1); + this.begin("mu"); + } else if(yy_.yytext.slice(-1) === "\\") { + strip(0,1); + this.begin("emu"); + } else { + this.begin("mu"); + } + if(yy_.yytext) return 14; + + break; + case 1:return 14; + break; + case 2: + this.popState(); + return 14; + + break; + case 3:strip(0,4); this.popState(); return 15; + break; + case 4:return 35; + break; + case 5:return 36; + break; + case 6:return 25; + break; + case 7:return 16; + break; + case 8:return 20; + break; + case 9:return 19; + break; + case 10:return 19; + break; + case 11:return 23; + break; + case 12:return 22; + break; + case 13:this.popState(); this.begin('com'); + break; + case 14:strip(3,5); this.popState(); return 15; + break; + case 15:return 22; + break; + case 16:return 41; + break; + case 17:return 40; + break; + case 18:return 40; + break; + case 19:return 44; + break; + case 20:// ignore whitespace + break; + case 21:this.popState(); return 24; + break; + case 22:this.popState(); return 18; + break; + case 23:yy_.yytext = strip(1,2).replace(/\\"/g,'"'); return 32; + break; + case 24:yy_.yytext = strip(1,2).replace(/\\'/g,"'"); return 32; + break; + case 25:return 42; + break; + case 26:return 34; + break; + case 27:return 34; + break; + case 28:return 33; + break; + case 29:return 40; + break; + case 30:yy_.yytext = strip(1,2); return 40; + break; + case 31:return 'INVALID'; + break; + case 32:return 5; + break; + } + }; + lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\()/,/^(?:\))/,/^(?:\{\{(~)?>)/,/^(?:\{\{(~)?#)/,/^(?:\{\{(~)?\/)/,/^(?:\{\{(~)?\^)/,/^(?:\{\{(~)?\s*else\b)/,/^(?:\{\{(~)?\{)/,/^(?:\{\{(~)?&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{(~)?)/,/^(?:=)/,/^(?:\.\.)/,/^(?:\.(?=([=~}\s\/.)])))/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}(~)?\}\})/,/^(?:(~)?\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@)/,/^(?:true(?=([~}\s)])))/,/^(?:false(?=([~}\s)])))/,/^(?:-?[0-9]+(?=([~}\s)])))/,/^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)]))))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:$)/]; + lexer.conditions = {"mu":{"rules":[4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"com":{"rules":[3],"inclusive":false},"INITIAL":{"rules":[0,1,32],"inclusive":true}}; + return lexer;})() + parser.lexer = lexer; + function Parser () { this.yy = {}; }Parser.prototype = parser;parser.Parser = Parser; + return new Parser; + })();__exports__["default"] = handlebars; + /* jshint ignore:end */ + }); +define("handlebars/compiler/printer", + ["./visitor","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Visitor = __dependency1__["default"]; + + function print(ast) { + return new PrintVisitor().accept(ast); + } + + __exports__.print = print;function PrintVisitor() { + this.padding = 0; + } + + __exports__.PrintVisitor = PrintVisitor;PrintVisitor.prototype = new Visitor(); + + PrintVisitor.prototype.pad = function(string, newline) { + var out = ""; + + for(var i=0,l=this.padding; i " + content + " }}"); + }; + + PrintVisitor.prototype.hash = function(hash) { + var pairs = hash.pairs; + var joinedPairs = [], left, right; + + for(var i=0, l=pairs.length; i 1) { + return "PATH:" + path; + } else { + return "ID:" + path; + } + }; + + PrintVisitor.prototype.PARTIAL_NAME = function(partialName) { + return "PARTIAL:" + partialName.name; + }; + + PrintVisitor.prototype.DATA = function(data) { + return "@" + this.accept(data.id); + }; + + PrintVisitor.prototype.content = function(content) { + return this.pad("CONTENT[ '" + content.string + "' ]"); + }; + + PrintVisitor.prototype.comment = function(comment) { + return this.pad("{{! '" + comment.comment + "' }}"); + }; + }); +define("handlebars/compiler/visitor", + ["exports"], + function(__exports__) { + "use strict"; + function Visitor() {} + + Visitor.prototype = { + constructor: Visitor, + + accept: function(object) { + return this[object.type](object); + } + }; + + __exports__["default"] = Visitor; + }); +define("handlebars/exception", + ["exports"], + function(__exports__) { + "use strict"; + + var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; + + function Exception(message, node) { + var line; + if (node && node.firstLine) { + line = node.firstLine; + + message += ' - ' + line + ':' + node.firstColumn; + } + + var tmp = Error.prototype.constructor.call(this, message); + + // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. + for (var idx = 0; idx < errorProps.length; idx++) { + this[errorProps[idx]] = tmp[errorProps[idx]]; + } + + if (line) { + this.lineNumber = line; + this.column = node.firstColumn; + } + } + + Exception.prototype = new Error(); + + __exports__["default"] = Exception; + }); +define("handlebars/runtime", + ["./utils","./exception","./base","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Utils = __dependency1__; + var Exception = __dependency2__["default"]; + var COMPILER_REVISION = __dependency3__.COMPILER_REVISION; + var REVISION_CHANGES = __dependency3__.REVISION_CHANGES; + + function checkRevision(compilerInfo) { + var compilerRevision = compilerInfo && compilerInfo[0] || 1, + currentRevision = COMPILER_REVISION; + + if (compilerRevision !== currentRevision) { + if (compilerRevision < currentRevision) { + var runtimeVersions = REVISION_CHANGES[currentRevision], + compilerVersions = REVISION_CHANGES[compilerRevision]; + throw new Exception("Template was precompiled with an older version of Handlebars than the current runtime. "+ + "Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+")."); + } else { + // Use the embedded version info since the runtime doesn't know about this revision yet + throw new Exception("Template was precompiled with a newer version of Handlebars than the current runtime. "+ + "Please update your runtime to a newer version ("+compilerInfo[1]+")."); + } + } + } + + __exports__.checkRevision = checkRevision;// TODO: Remove this line and break up compilePartial + + function template(templateSpec, env) { + if (!env) { + throw new Exception("No environment passed to template"); + } + + // Note: Using env.VM references rather than local var references throughout this section to allow + // for external users to override these as psuedo-supported APIs. + var invokePartialWrapper = function(partial, name, context, helpers, partials, data) { + var result = env.VM.invokePartial.apply(this, arguments); + if (result != null) { return result; } + + if (env.compile) { + var options = { helpers: helpers, partials: partials, data: data }; + partials[name] = env.compile(partial, { data: data !== undefined }, env); + return partials[name](context, options); + } else { + throw new Exception("The partial " + name + " could not be compiled when running in runtime-only mode"); + } + }; + + // Just add water + var container = { + escapeExpression: Utils.escapeExpression, + invokePartial: invokePartialWrapper, + programs: [], + program: function(i, fn, data) { + var programWrapper = this.programs[i]; + if(data) { + programWrapper = program(i, fn, data); + } else if (!programWrapper) { + programWrapper = this.programs[i] = program(i, fn); + } + return programWrapper; + }, + merge: function(param, common) { + var ret = param || common; + + if (param && common && (param !== common)) { + ret = {}; + Utils.extend(ret, common); + Utils.extend(ret, param); + } + return ret; + }, + programWithDepth: env.VM.programWithDepth, + noop: env.VM.noop, + compilerInfo: null + }; + + return function(context, options) { + options = options || {}; + var namespace = options.partial ? options : env, + helpers, + partials; + + if (!options.partial) { + helpers = options.helpers; + partials = options.partials; + } + var result = templateSpec.call( + container, + namespace, context, + helpers, + partials, + options.data); + + if (!options.partial) { + env.VM.checkRevision(container.compilerInfo); + } + + return result; + }; + } + + __exports__.template = template;function programWithDepth(i, fn, data /*, $depth */) { + var args = Array.prototype.slice.call(arguments, 3); + + var prog = function(context, options) { + options = options || {}; + + return fn.apply(this, [context, options.data || data].concat(args)); + }; + prog.program = i; + prog.depth = args.length; + return prog; + } + + __exports__.programWithDepth = programWithDepth;function program(i, fn, data) { + var prog = function(context, options) { + options = options || {}; + + return fn(context, options.data || data); + }; + prog.program = i; + prog.depth = 0; + return prog; + } + + __exports__.program = program;function invokePartial(partial, name, context, helpers, partials, data) { + var options = { partial: true, helpers: helpers, partials: partials, data: data }; + + if(partial === undefined) { + throw new Exception("The partial " + name + " could not be found"); + } else if(partial instanceof Function) { + return partial(context, options); + } + } + + __exports__.invokePartial = invokePartial;function noop() { return ""; } + + __exports__.noop = noop; + }); +define("handlebars/safe-string", + ["exports"], + function(__exports__) { + "use strict"; + // Build out our basic SafeString type + function SafeString(string) { + this.string = string; + } + + SafeString.prototype.toString = function() { + return "" + this.string; + }; + + __exports__["default"] = SafeString; + }); +define("handlebars/utils", + ["./safe-string","exports"], + function(__dependency1__, __exports__) { + "use strict"; + /*jshint -W004 */ + var SafeString = __dependency1__["default"]; + + var escape = { + "&": "&", + "<": "<", + ">": ">", + '"': """, + "'": "'", + "`": "`" + }; + + var badChars = /[&<>"'`]/g; + var possible = /[&<>"'`]/; + + function escapeChar(chr) { + return escape[chr] || "&"; + } + + function extend(obj, value) { + for(var key in value) { + if(Object.prototype.hasOwnProperty.call(value, key)) { + obj[key] = value[key]; + } + } + } + + __exports__.extend = extend;var toString = Object.prototype.toString; + __exports__.toString = toString; + // Sourced from lodash + // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt + var isFunction = function(value) { + return typeof value === 'function'; + }; + // fallback for older versions of Chrome and Safari + if (isFunction(/x/)) { + isFunction = function(value) { + return typeof value === 'function' && toString.call(value) === '[object Function]'; + }; + } + var isFunction; + __exports__.isFunction = isFunction; + var isArray = Array.isArray || function(value) { + return (value && typeof value === 'object') ? toString.call(value) === '[object Array]' : false; + }; + __exports__.isArray = isArray; + + function escapeExpression(string) { + // don't escape SafeStrings, since they're already safe + if (string instanceof SafeString) { + return string.toString(); + } else if (!string && string !== 0) { + return ""; + } + + // Force a string conversion as this will be done by the append regardless and + // the regex test will do this transparently behind the scenes, causing issues if + // an object's to string has escaped characters in it. + string = "" + string; + + if(!possible.test(string)) { return string; } + return string.replace(badChars, escapeChar); + } + + __exports__.escapeExpression = escapeExpression;function isEmpty(value) { + if (!value && value !== 0) { + return true; + } else if (isArray(value) && value.length === 0) { + return true; + } else { + return false; + } + } + + __exports__.isEmpty = isEmpty; + }); +define("htmlbars-compiler", + ["./htmlbars-compiler/compiler","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var compilerSpec = __dependency1__.compilerSpec; + var compilerSpec; + __exports__.compilerSpec = compilerSpec; + }); +define("htmlbars-compiler/ast", + ["../handlebars/compiler/ast","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var AST = __dependency1__["default"]; + + var MustacheNode = AST.MustacheNode; + __exports__.MustacheNode = MustacheNode;var SexprNode = AST.SexprNode; + __exports__.SexprNode = SexprNode;var HashNode = AST.HashNode; + __exports__.HashNode = HashNode;var IdNode = AST.IdNode; + __exports__.IdNode = IdNode;var StringNode = AST.StringNode; + __exports__.StringNode = StringNode; + function ProgramNode(statements, strip) { + this.type = 'program'; + this.statements = statements; + this.strip = strip; + } + + __exports__.ProgramNode = ProgramNode;function BlockNode(mustache, program, inverse, strip) { + this.type = 'block'; + this.mustache = mustache; + this.program = program; + this.inverse = inverse; + this.strip = strip; + } + + __exports__.BlockNode = BlockNode;function ComponentNode(tag, attributes, program) { + this.type = 'component'; + this.tag = tag; + this.attributes = attributes; + this.program = program; + } + + __exports__.ComponentNode = ComponentNode;function ElementNode(tag, attributes, helpers, children) { + this.type = 'element'; + this.tag = tag; + this.attributes = attributes; + this.helpers = helpers; + this.children = children; + } + + __exports__.ElementNode = ElementNode;function PartialNode(name) { + this.id = {}; + this.id.string = this.name = 'partial'; + this.type = 'mustache'; + this.params = [name]; + this.program = null; + this.inverse = null; + this.hash = undefined; + this.escaped = true; + this.isHelper = true; + } + + __exports__.PartialNode = PartialNode;function AttrNode(name, value) { + this.type = 'attr'; + this.name = name; + this.value = value; + } + + __exports__.AttrNode = AttrNode;function TextNode(chars) { + this.type = 'text'; + this.chars = chars; + } + + __exports__.TextNode = TextNode;function childrenFor(node) { + if (node.type === 'program') return node.statements; + if (node.type === 'element') return node.children; + } + + __exports__.childrenFor = childrenFor;function usesMorph(node) { + return node.type === 'mustache' || node.type === 'block' || node.type === 'component'; + } + + __exports__.usesMorph = usesMorph;function appendChild(parent, node) { + var children = childrenFor(parent); + + var len = children.length, last; + if (len > 0) { + last = children[len-1]; + if (usesMorph(last) && usesMorph(node)) { + children.push(new TextNode('')); + } + } + children.push(node); + } + + __exports__.appendChild = appendChild; + }); +define("htmlbars-compiler/compiler", + ["./parser","./compiler/template","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + /*jshint evil:true*/ + var preprocess = __dependency1__.preprocess; + var TemplateCompiler = __dependency2__.TemplateCompiler; + + /* + * Compile a string into a template rendering function + * + * Example usage: + * + * // Template is the hydration portion of the compiled template + * var template = compile("Howdy {{name}}"); + * + * // Template accepts three arguments: + * // + * // 1. A context object + * // 2. An env object + * // 3. A contextualElement (optional, document.body is the default) + * // + * // The env object *must* have at least these two properties: + * // + * // 1. `hooks` - Basic hooks for rendering a template + * // 2. `dom` - An instance of DOMHelper + * // + * import {hooks} from 'htmlbars-runtime'; + * import {DOMHelper} from 'morph'; + * var context = {name: 'whatever'}, + * env = {hooks: hooks, dom: new DOMHelper()}, + * contextualElement = document.body; + * var domFragment = template(context, env, contextualElement); + * + * @method compile + * @param {String} string An htmlbars template string + * @return {Function} A function for rendering the template + */ + function compile(string) { + var program = compileSpec(string); + return new Function("return " + program)(); + } + + __exports__.compile = compile;/* + * Compile a string into a template spec string. The template spec is a string + * representation of a template. Usually, you would use compileSpec for + * pre-compilation of a template on the server. + * + * Example usage: + * + * var templateSpec = compileSpec("Howdy {{name}}"); + * // This next step is basically what plain compile does + * var template = new Function("return " + templateSpec)(); + * + * @method compileSpec + * @param {String} string An htmlbars template string + * @return {Function} A template spec string + */ + function compileSpec(string) { + var ast = preprocess(string); + var compiler = new TemplateCompiler(); + var program = compiler.compile(ast); + return program; + } + + __exports__.compileSpec = compileSpec; + }); +define("htmlbars-compiler/compiler/fragment", + ["./utils","./quoting","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var processOpcodes = __dependency1__.processOpcodes; + var string = __dependency2__.string; + + function FragmentCompiler() { + this.source = []; + this.depth = -1; + } + + __exports__.FragmentCompiler = FragmentCompiler;FragmentCompiler.prototype.compile = function(opcodes, options) { + this.source.length = 0; + this.depth = -1; + this.indent = (options && options.indent) || ""; + + this.source.push(this.indent+'function build(dom) {\n'); + processOpcodes(this, opcodes); + this.source.push(this.indent+'}\n'); + + return this.source.join(''); + }; + + FragmentCompiler.prototype.createFragment = function() { + var el = 'el'+(++this.depth); + this.source.push(this.indent+' var '+el+' = dom.createDocumentFragment();\n'); + }; + + FragmentCompiler.prototype.createElement = function(tagName) { + var el = 'el'+(++this.depth); + this.source.push(this.indent+' var '+el+' = dom.createElement('+string(tagName)+');\n'); + }; + + FragmentCompiler.prototype.createText = function(str) { + var el = 'el'+(++this.depth); + this.source.push(this.indent+' var '+el+' = dom.createTextNode('+string(str)+');\n'); + }; + + FragmentCompiler.prototype.returnNode = function() { + var el = 'el'+this.depth; + this.source.push(this.indent+' return '+el+';\n'); + }; + + FragmentCompiler.prototype.setAttribute = function(name, value) { + var el = 'el'+this.depth; + this.source.push(this.indent+' dom.setAttribute('+el+','+string(name)+','+string(value)+');\n'); + }; + + FragmentCompiler.prototype.appendChild = function() { + var child = 'el'+(this.depth--); + var el = 'el'+this.depth; + this.source.push(this.indent+' dom.appendChild('+el+', '+child+');\n'); + }; + + FragmentCompiler.prototype.setNamespace = function(namespace) { + this.source.push(this.indent+' dom.setNamespace('+(namespace ? string(namespace) : 'null')+');\n'); + }; + }); +define("htmlbars-compiler/compiler/fragment_opcode", + ["./template_visitor","./utils","../utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var TemplateVisitor = __dependency1__["default"]; + var processOpcodes = __dependency2__.processOpcodes; + var forEach = __dependency3__.forEach; + + function FragmentOpcodeCompiler() { + this.opcodes = []; + } + + FragmentOpcodeCompiler.prototype.compile = function(ast) { + var templateVisitor = new TemplateVisitor(); + templateVisitor.visit(ast); + + processOpcodes(this, templateVisitor.actions); + + return this.opcodes; + }; + + FragmentOpcodeCompiler.prototype.opcode = function(type, params) { + this.opcodes.push([type, params]); + }; + + FragmentOpcodeCompiler.prototype.text = function(text, childIndex, childCount, isSingleRoot) { + this.opcode('createText', [text.chars]); + if (!isSingleRoot) { this.opcode('appendChild'); } + }; + + FragmentOpcodeCompiler.prototype.openElement = function(element) { + this.opcode('createElement', [element.tag]); + forEach(element.attributes, this.attribute, this); + }; + + FragmentOpcodeCompiler.prototype.closeElement = function(element, childIndex, childCount, isSingleRoot) { + if (!isSingleRoot) { this.opcode('appendChild'); } + }; + + FragmentOpcodeCompiler.prototype.startProgram = function(program) { + this.opcodes.length = 0; + if (program.statements.length !== 1) { + this.opcode('createFragment'); + } + }; + + FragmentOpcodeCompiler.prototype.endProgram = function(program) { + this.opcode('returnNode'); + }; + + FragmentOpcodeCompiler.prototype.mustache = function () {}; + + FragmentOpcodeCompiler.prototype.component = function () {}; + + FragmentOpcodeCompiler.prototype.block = function () {}; + + FragmentOpcodeCompiler.prototype.attribute = function(attr) { + if (attr.value.type === 'text') { + this.opcode('setAttribute', [attr.name, attr.value.chars]); + } + }; + + FragmentOpcodeCompiler.prototype.setNamespace = function(namespace) { + this.opcode('setNamespace', [namespace]); + }; + + __exports__.FragmentOpcodeCompiler = FragmentOpcodeCompiler; + }); +define("htmlbars-compiler/compiler/helpers", + ["./quoting","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var array = __dependency1__.array; + var hash = __dependency1__.hash; + var string = __dependency1__.string; + + function prepareHelper(stack, size) { + var args = [], + types = [], + hashPairs = [], + hashTypes = [], + keyName, + i; + + var hashSize = stack.pop(); + + for (i=0; i 0){ + this.opcode( 'repairClonedNode', + blankChildTextNodes ); + } + }; + + HydrationOpcodeCompiler.prototype.endProgram = function(program) { + distributeMorphs(this.morphs, this.opcodes); + }; + + HydrationOpcodeCompiler.prototype.text = function(string, pos, len) { + ++this.currentDOMChildIndex; + }; + + HydrationOpcodeCompiler.prototype.openElement = function(element, pos, len, isSingleRoot, mustacheCount, blankChildTextNodes) { + distributeMorphs(this.morphs, this.opcodes); + ++this.currentDOMChildIndex; + + this.element = this.currentDOMChildIndex; + + if (!isSingleRoot) { + this.opcode('consumeParent', this.currentDOMChildIndex); + + // If our parent referance will be used more than once, cache its referance. + if (mustacheCount > 1) { + this.opcode('element', ++this.elementNum); + this.element = null; // Set element to null so we don't cache it twice + } + } + var isElementChecked = detectIsElementChecked(element); + if (blankChildTextNodes.length > 0 || isElementChecked) { + this.opcode( 'repairClonedNode', + blankChildTextNodes, + isElementChecked ); + } + + this.paths.push(this.currentDOMChildIndex); + this.currentDOMChildIndex = -1; + + forEach(element.attributes, this.attribute, this); + forEach(element.helpers, this.nodeHelper, this); + }; + + HydrationOpcodeCompiler.prototype.closeElement = function(element, pos, len, isSingleRoot) { + distributeMorphs(this.morphs, this.opcodes); + if (!isSingleRoot) { this.opcode('popParent'); } + this.currentDOMChildIndex = this.paths.pop(); + }; + + HydrationOpcodeCompiler.prototype.block = function(block, childIndex, childrenLength) { + var currentDOMChildIndex = this.currentDOMChildIndex, + mustache = block.mustache; + + var start = (currentDOMChildIndex < 0 ? null : currentDOMChildIndex), + end = (childIndex === childrenLength - 1 ? null : currentDOMChildIndex + 1); + + var morphNum = this.morphNum++; + this.morphs.push([morphNum, this.paths.slice(), start, end]); + + this.opcode('program', this.templateId++, block.inverse === null ? null : this.templateId++); + processParams(this, mustache.params); + processHash(this, mustache.hash); + this.opcode('helper', mustache.id.string, mustache.params.length, mustache.escaped, morphNum); + }; + + HydrationOpcodeCompiler.prototype.component = function(component, childIndex, childrenLength) { + var currentDOMChildIndex = this.currentDOMChildIndex; + + var start = (currentDOMChildIndex < 0 ? null : currentDOMChildIndex), + end = (childIndex === childrenLength - 1 ? null : currentDOMChildIndex + 1); + + var morphNum = this.morphNum++; + this.morphs.push([morphNum, this.paths.slice(), start, end]); + + this.opcode('program', this.templateId++, null); + processHash(this, buildHashFromAttributes(component.attributes)); + this.opcode('component', component.tag, morphNum); + }; + + HydrationOpcodeCompiler.prototype.opcode = function(type) { + var params = [].slice.call(arguments, 1); + this.opcodes.push([type, params]); + }; + + HydrationOpcodeCompiler.prototype.attribute = function(attr) { + if (attr.value.type === 'text') return; + + // We treat attribute like a attribute helper evaluated by the element hook. + //

+ // Unwrapped any mustaches to just be their internal sexprs. + this.nodeHelper({ + params: [attr.name, attr.value.sexpr], + hash: null, + id: { + string: 'attribute' + } + }); + }; + + HydrationOpcodeCompiler.prototype.nodeHelper = function(mustache) { + this.opcode('program', null, null); + processParams(this, mustache.params); + processHash(this, mustache.hash); + // If we have a helper in a node, and this element has not been cached, cache it + if(this.element !== null){ + this.opcode('element', ++this.elementNum); + this.element = null; // Reset element so we don't cache it more than once + } + this.opcode('nodeHelper', mustache.id.string, mustache.params.length, this.elementNum); + }; + + HydrationOpcodeCompiler.prototype.mustache = function(mustache, childIndex, childrenLength) { + var currentDOMChildIndex = this.currentDOMChildIndex; + + var start = currentDOMChildIndex, + end = (childIndex === childrenLength - 1 ? -1 : currentDOMChildIndex + 1); + + var morphNum = this.morphNum++; + this.morphs.push([morphNum, this.paths.slice(), start, end]); + + if (mustache.isHelper) { + this.opcode('program', null, null); + processParams(this, mustache.params); + processHash(this, mustache.hash); + this.opcode('helper', mustache.id.string, mustache.params.length, mustache.escaped, morphNum); + } else { + this.opcode('ambiguous', mustache.id.string, mustache.escaped, morphNum); + } + }; + + HydrationOpcodeCompiler.prototype.sexpr = function(sexpr) { + this.string('sexpr'); + this.opcode('program', null, null); + processParams(this, sexpr.params); + processHash(this, sexpr.hash); + this.opcode('sexpr', sexpr.id.string, sexpr.params.length); + }; + + HydrationOpcodeCompiler.prototype.string = function(str) { + this.opcode('string', str); + }; + + HydrationOpcodeCompiler.prototype.mustacheInAttr = function(mustache) { + if (mustache.isHelper) { + this.opcode('program', null, null); + processParams(this, mustache.params); + processHash(this, mustache.hash); + this.opcode('helperAttr', mustache.id.string, mustache.params.length, mustache.escaped); + } else { + this.opcode('ambiguousAttr', mustache.id.string, mustache.escaped); + } + }; + + HydrationOpcodeCompiler.prototype.ID = function(id) { + this.opcode('id', id.parts); + }; + + HydrationOpcodeCompiler.prototype.STRING = function(string) { + this.opcode('stringLiteral', string.stringModeValue); + }; + + HydrationOpcodeCompiler.prototype.BOOLEAN = function(boolean) { + this.opcode('literal', boolean.stringModeValue); + }; + + HydrationOpcodeCompiler.prototype.INTEGER = function(integer) { + this.opcode('literal', integer.stringModeValue); + }; + + function processParams(compiler, params) { + forEach(params, function(param) { + if (param.type === 'text') { + compiler.STRING({ stringModeValue: param.chars }); + } else if (param.type) { + compiler[param.type](param); + } else { + compiler.STRING({ stringModeValue: param }); + } + }); + } + + function processHash(compiler, hash) { + if (hash) { + forEach(hash.pairs, function(pair) { + var name = pair[0], param = pair[1]; + compiler[param.type](param); + compiler.opcode('stackLiteral', name); + }); + compiler.opcode('stackLiteral', hash.pairs.length); + } else { + compiler.opcode('stackLiteral', 0); + } + } + + function distributeMorphs(morphs, opcodes) { + if (morphs.length === 0) { + return; + } + + // Splice morphs after the most recent shareParent/consumeParent. + var o; + for (o = opcodes.length - 1; o >= 0; --o) { + var opcode = opcodes[o][0]; + if (opcode === 'element' || opcode === 'consumeParent' || opcode === 'popParent') { + break; + } + } + + var spliceArgs = [o + 1, 0]; + for (var i = 0; i < morphs.length; ++i) { + var p = morphs[i]; + spliceArgs.push(['morph', [p[0], p[1], p[2], p[3]]]); + } + opcodes.splice.apply(opcodes, spliceArgs); + morphs.length = 0; + } + + __exports__.HydrationOpcodeCompiler = HydrationOpcodeCompiler; + }); +define("htmlbars-compiler/compiler/quoting", + ["exports"], + function(__exports__) { + "use strict"; + function escapeString(str) { + return str.replace(/"/g, '\\"').replace(/\n/g, "\\n"); + } + + __exports__.escapeString = escapeString; + + function string(str) { + return '"' + escapeString(str) + '"'; + } + + __exports__.string = string; + + function array(a) { + return "[" + a + "]"; + } + + __exports__.array = array; + + function quotedArray(list) { + return array(list.map(string).join(", ")); + } + + __exports__.quotedArray = quotedArray;function hash(pairs) { + return "{" + pairs.join(",") + "}"; + } + + __exports__.hash = hash;function repeat(chars, times) { + var str = ""; + while (times--) { + str += chars; + } + return str; + } + + __exports__.repeat = repeat; + }); +define("htmlbars-compiler/compiler/template", + ["./fragment_opcode","./fragment","./hydration_opcode","./hydration","./template_visitor","./utils","./quoting","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var FragmentOpcodeCompiler = __dependency1__.FragmentOpcodeCompiler; + var FragmentCompiler = __dependency2__.FragmentCompiler; + var HydrationOpcodeCompiler = __dependency3__.HydrationOpcodeCompiler; + var HydrationCompiler = __dependency4__.HydrationCompiler; + var TemplateVisitor = __dependency5__["default"]; + var processOpcodes = __dependency6__.processOpcodes; + var string = __dependency7__.string; + var repeat = __dependency7__.repeat; + + function TemplateCompiler() { + this.fragmentOpcodeCompiler = new FragmentOpcodeCompiler(); + this.fragmentCompiler = new FragmentCompiler(); + this.hydrationOpcodeCompiler = new HydrationOpcodeCompiler(); + this.hydrationCompiler = new HydrationCompiler(); + this.templates = []; + this.childTemplates = []; + } + + __exports__.TemplateCompiler = TemplateCompiler;TemplateCompiler.prototype.compile = function(ast) { + var templateVisitor = new TemplateVisitor(); + templateVisitor.visit(ast); + + processOpcodes(this, templateVisitor.actions); + + return this.templates.pop(); + }; + + TemplateCompiler.prototype.startProgram = function(program, childTemplateCount, blankChildTextNodes) { + this.fragmentOpcodeCompiler.startProgram(program, childTemplateCount, blankChildTextNodes); + this.hydrationOpcodeCompiler.startProgram(program, childTemplateCount, blankChildTextNodes); + + this.childTemplates.length = 0; + while(childTemplateCount--) { + this.childTemplates.push(this.templates.pop()); + } + }; + + TemplateCompiler.prototype.endProgram = function(program, programDepth) { + this.fragmentOpcodeCompiler.endProgram(program); + this.hydrationOpcodeCompiler.endProgram(program); + + var indent = repeat(" ", programDepth); + var options = { + indent: indent + " " + }; + + // function build(dom) { return fragment; } + var fragmentProgram = this.fragmentCompiler.compile( + this.fragmentOpcodeCompiler.opcodes, + options + ); + + // function hydrate(fragment) { return mustaches; } + var hydrationProgram = this.hydrationCompiler.compile( + this.hydrationOpcodeCompiler.opcodes, + options + ); + + var childTemplateVars = ""; + for (var i=0, l=this.childTemplates.length; ibaz + * + * produces the actions + * + * [['startProgram', [programNode, 0]], + * ['text', [textNode, 0, 3]], + * ['mustache', [mustacheNode, 1, 3]], + * ['openElement', [elementNode, 2, 3, 0]], + * ['text', [textNode, 0, 1]], + * ['closeElement', [elementNode, 2, 3], + * ['endProgram', [programNode]]] + * + * This visitor walks the AST depth first and backwards. As + * a result the bottom-most child template will appear at the + * top of the actions list whereas the root template will appear + * at the bottom of the list. For example, + * + *
{{#if}}foo{{else}}bar{{/if}}
+ * + * produces the actions + * + * [['startProgram', [programNode, 0]], + * ['text', [textNode, 0, 2, 0]], + * ['openElement', [elementNode, 1, 2, 0]], + * ['closeElement', [elementNode, 1, 2]], + * ['endProgram', [programNode]], + * ['startProgram', [programNode, 0]], + * ['text', [textNode, 0, 1]], + * ['endProgram', [programNode]], + * ['startProgram', [programNode, 2]], + * ['openElement', [elementNode, 0, 1, 1]], + * ['block', [blockNode, 0, 1]], + * ['closeElement', [elementNode, 0, 1]], + * ['endProgram', [programNode]]] + * + * The state of the traversal is maintained by a stack of frames. + * Whenever a node with children is entered (either a ProgramNode + * or an ElementNode) a frame is pushed onto the stack. The frame + * contains information about the state of the traversal of that + * node. For example, + * + * - index of the current child node being visited + * - the number of mustaches contained within its child nodes + * - the list of actions generated by its child nodes + */ + + function TemplateVisitor() { + this.frameStack = []; + this.actions = []; + this.programDepth = -1; + } + + // Traversal methods + + TemplateVisitor.prototype.visit = function(node) { + this[node.type](node); + }; + + TemplateVisitor.prototype.program = function(program) { + this.programDepth++; + + var parentFrame = this.getCurrentFrame(); + var programFrame = this.pushFrame(); + + programFrame.parentNode = program; + programFrame.children = program.statements; + programFrame.childCount = program.statements.length; + programFrame.blankChildTextNodes = []; + programFrame.actions.push(['endProgram', [program, this.programDepth]]); + + for (var i = program.statements.length - 1; i >= 0; i--) { + programFrame.childIndex = i; + this.visit(program.statements[i]); + } + + programFrame.actions.push(['startProgram', [ + program, programFrame.childTemplateCount, programFrame.blankChildTextNodes.reverse() ]]); + this.popFrame(); + + this.programDepth--; + + // Push the completed template into the global actions list + if (parentFrame) { parentFrame.childTemplateCount++; } + push.apply(this.actions, programFrame.actions.reverse()); + }; + + TemplateVisitor.prototype.element = function(element) { + var parentFrame = this.getCurrentFrame(); + var elementFrame = this.pushFrame(); + var parentNode = parentFrame.parentNode; + + elementFrame.parentNode = element; + elementFrame.children = element.children; + elementFrame.childCount = element.children.length; + elementFrame.mustacheCount += element.helpers.length; + elementFrame.blankChildTextNodes = []; + + var actionArgs = [ + element, + parentFrame.childIndex, + parentFrame.childCount, + parentNode.type === 'program' && parentFrame.childCount === 1 + ]; + + var lastNode = parentFrame.childIndex === parentFrame.childCount-1, + introducesNamespace = elementIntroducesNamespace(element, parentFrame.parentNode); + if ( !lastNode && introducesNamespace ) { + elementFrame.actions.push(['setNamespace', [parentNode.namespaceURI]]); + } + elementFrame.actions.push(['closeElement', actionArgs]); + if ( !lastNode && element.isHTMLIntergrationPoint ) { + elementFrame.actions.push(['setNamespace', []]); + } + + for (var i = element.attributes.length - 1; i >= 0; i--) { + this.visit(element.attributes[i]); + } + + for (i = element.children.length - 1; i >= 0; i--) { + elementFrame.childIndex = i; + this.visit(element.children[i]); + } + + if ( element.isHTMLIntergrationPoint ) { + elementFrame.actions.push(['setNamespace', []]); + } + elementFrame.actions.push(['openElement', actionArgs.concat([ + elementFrame.mustacheCount, elementFrame.blankChildTextNodes.reverse() ])]); + if ( introducesNamespace ) { + elementFrame.actions.push(['setNamespace', [element.namespaceURI]]); + } + this.popFrame(); + + // Propagate the element's frame state to the parent frame + if (elementFrame.mustacheCount > 0) { parentFrame.mustacheCount++; } + parentFrame.childTemplateCount += elementFrame.childTemplateCount; + push.apply(parentFrame.actions, elementFrame.actions); + }; + + TemplateVisitor.prototype.attr = function(attr) { + if (attr.value.type === 'mustache') { + this.getCurrentFrame().mustacheCount++; + } + }; + + TemplateVisitor.prototype.block = function(node) { + var frame = this.getCurrentFrame(); + var parentNode = frame.parentNode; + + frame.mustacheCount++; + frame.actions.push([node.type, [node, frame.childIndex, frame.childCount]]); + + if (node.inverse) { this.visit(node.inverse); } + if (node.program) { this.visit(node.program); } + }; + + TemplateVisitor.prototype.partial = function(node) { + var frame = this.getCurrentFrame(); + frame.mustacheCount++; + frame.actions.push(['mustache', [node, frame.childIndex, frame.childCount]]); + }; + + TemplateVisitor.prototype.component = TemplateVisitor.prototype.block; + + TemplateVisitor.prototype.text = function(text) { + var frame = this.getCurrentFrame(); + var isSingleRoot = frame.parentNode.type === 'program' && frame.childCount === 1; + if (text.chars === '') { + frame.blankChildTextNodes.push(domIndexOf(frame.children, text)); + } + frame.actions.push(['text', [text, frame.childIndex, frame.childCount, isSingleRoot]]); + }; + + TemplateVisitor.prototype.mustache = function(mustache) { + var frame = this.getCurrentFrame(); + frame.mustacheCount++; + frame.actions.push(['mustache', [mustache, frame.childIndex, frame.childCount]]); + }; + + // Frame helpers + + TemplateVisitor.prototype.getCurrentFrame = function() { + return this.frameStack[this.frameStack.length - 1]; + }; + + TemplateVisitor.prototype.pushFrame = function() { + var frame = new Frame(); + this.frameStack.push(frame); + return frame; + }; + + TemplateVisitor.prototype.popFrame = function() { + return this.frameStack.pop(); + }; + + __exports__["default"] = TemplateVisitor; + + + // Returns the index of `domNode` in the `nodes` array, skipping + // over any nodes which do not represent DOM nodes. + function domIndexOf(nodes, domNode) { + var index = -1; + + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; + + if (node.type !== 'text' && node.type !== 'element') { + continue; + } else { + index++; + } + + if (node === domNode) { + return index; + } + } + + return -1; + } + }); +define("htmlbars-compiler/compiler/utils", + ["exports"], + function(__exports__) { + "use strict"; + function processOpcodes(compiler, opcodes) { + for (var i=0, l=opcodes.length; i 0 && statements[i-1].strip && statements[i-1].strip.right) || + (i === 0 && program.strip.left)) { + statement.chars = statement.chars.replace(/^\s+/, ''); + } + + if ((i < l-1 && statements[i+1].strip && statements[i+1].strip.left) || + (i === l-1 && program.strip.right)) { + statement.chars = statement.chars.replace(/\s+$/, ''); + } + + // Remove unnecessary text nodes + if (statement.chars.length === 0) { + if ((i > 0 && statements[i-1].type === 'element') || + (i < l-1 && statements[i+1].type === 'element')) { + statements.splice(i, 1); + i--; + l--; + } + } + } + } + + __exports__.postprocessProgram = postprocessProgram; + }); +define("htmlbars-compiler/html-parser/node-handlers", + ["../ast","../html-parser/helpers","../html-parser/tokens","../utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var BlockNode = __dependency1__.BlockNode; + var ProgramNode = __dependency1__.ProgramNode; + var TextNode = __dependency1__.TextNode; + var PartialNode = __dependency1__.PartialNode; + var appendChild = __dependency1__.appendChild; + var usesMorph = __dependency1__.usesMorph; + var postprocessProgram = __dependency2__.postprocessProgram; + var Chars = __dependency3__.Chars; + var forEach = __dependency4__.forEach; + + var nodeHandlers = { + + program: function(program) { + var statements = []; + var node = new ProgramNode(statements, program.strip); + var i, l = program.statements.length; + + this.elementStack.push(node); + + if (l === 0) { return this.elementStack.pop(); } + + for (i = 0; i < l; i++) { + this.acceptNode(program.statements[i]); + } + + this.acceptToken(this.tokenizer.tokenizeEOF()); + + postprocessProgram(node); + + // Ensure that that the element stack is balanced properly. + var poppedNode = this.elementStack.pop(); + if (poppedNode !== node) { + throw new Error("Unclosed element: " + poppedNode.tag); + } + + return node; + }, + + block: function(block) { + switchToHandlebars(this); + this.acceptToken(block); + + var mustache = block.mustache; + var program = this.acceptNode(block.program); + var inverse = block.inverse ? this.acceptNode(block.inverse) : null; + var strip = block.strip; + + // Normalize inverse's strip + if (inverse && !inverse.strip.left) { + inverse.strip.left = false; + } + + var node = new BlockNode(mustache, program, inverse, strip); + var parentProgram = this.currentElement(); + appendChild(parentProgram, node); + }, + + content: function(content) { + var tokens = this.tokenizer.tokenizePart(content.string); + + return forEach(tokens, this.acceptToken, this); + }, + + mustache: function(mustache) { + switchToHandlebars(this); + this.acceptToken(mustache); + }, + + comment: function(comment) { + return; + }, + + partial: function(partial) { + var node = new PartialNode(partial.partialName.name); + appendChild(this.currentElement(), node); + return; + } + }; + + function switchToHandlebars(processor) { + var token = processor.tokenizer.token; + + // TODO: Monkey patch Chars.addChar like attributes + if (token instanceof Chars) { + processor.acceptToken(token); + processor.tokenizer.token = null; + } + } + + __exports__["default"] = nodeHandlers; + }); +define("htmlbars-compiler/html-parser/token-handlers", + ["../ast","./helpers","../utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var ProgramNode = __dependency1__.ProgramNode; + var ComponentNode = __dependency1__.ComponentNode; + var ElementNode = __dependency1__.ElementNode; + var TextNode = __dependency1__.TextNode; + var appendChild = __dependency1__.appendChild; + var postprocessProgram = __dependency2__.postprocessProgram; + var forEach = __dependency3__.forEach; + + // This table maps from the state names in the tokenizer to a smaller + // number of states that control how mustaches are handled + var states = { + "beforeAttributeValue": "before-attr", + "attributeValueDoubleQuoted": "attr", + "attributeValueSingleQuoted": "attr", + "attributeValueUnquoted": "attr", + "beforeAttributeName": "in-tag" + }; + + // The HTML elements in this list are speced by + // http://www.w3.org/TR/html-markup/syntax.html#syntax-elements, + // and will be forced to close regardless of if they have a + // self-closing /> at the end. + var voidTagNames = "area base br col command embed hr img input keygen link meta param source track wbr"; + var voidMap = {}; + + forEach(voidTagNames.split(" "), function(tagName) { + voidMap[tagName] = true; + }); + + var svgNamespace = "http://www.w3.org/2000/svg", + // http://www.w3.org/html/wg/drafts/html/master/syntax.html#html-integration-point + svgHTMLIntegrationPoints = {'foreignObject':true, 'desc':true, 'title':true}; + + function applyNamespace(tag, element, currentElement){ + if (tag.tagName === 'svg') { + element.namespaceURI = svgNamespace; + } else if ( + currentElement.type === 'element' && + currentElement.namespaceURI && + !currentElement.isHTMLIntegrationPoint + ) { + element.namespaceURI = currentElement.namespaceURI; + } + } + + function applyHTMLIntegrationPoint(tag, element){ + if (svgHTMLIntegrationPoints[tag.tagName]) { + element.isHTMLIntegrationPoint = true; + } + } + + + // Except for `mustache`, all tokens are only allowed outside of + // a start or end tag. + var tokenHandlers = { + + Chars: function(token) { + var current = this.currentElement(); + var text = new TextNode(token.chars); + appendChild(current, text); + }, + + StartTag: function(tag) { + var element = new ElementNode(tag.tagName, tag.attributes, tag.helpers || [], []); + applyNamespace(tag, element, this.currentElement()); + applyHTMLIntegrationPoint(tag, element); + this.elementStack.push(element); + if (voidMap.hasOwnProperty(tag.tagName) || tag.selfClosing) { + tokenHandlers.EndTag.call(this, tag); + } + }, + + block: function(block) { + if (this.tokenizer.state !== 'data') { + throw new Error("A block may only be used inside an HTML element or another block."); + } + }, + + mustache: function(mustache) { + var state = this.tokenizer.state; + var token = this.tokenizer.token; + + switch(states[state]) { + case "before-attr": + this.tokenizer.state = 'attributeValueUnquoted'; + token.addToAttributeValue(mustache); + return; + case "attr": + token.addToAttributeValue(mustache); + return; + case "in-tag": + token.addTagHelper(mustache); + return; + default: + appendChild(this.currentElement(), mustache); + } + }, + + EndTag: function(tag) { + var element = this.elementStack.pop(); + var parent = this.currentElement(); + + if (element.tag !== tag.tagName) { + throw new Error("Closing tag " + tag.tagName + " did not match last open tag " + element.tag); + } + + if (element.tag.indexOf("-") === -1) { + appendChild(parent, element); + } else { + var program = new ProgramNode(element.children, { left: false, right: false }); + postprocessProgram(program); + var component = new ComponentNode(element.tag, element.attributes, program); + appendChild(parent, component); + } + + } + + }; + + __exports__["default"] = tokenHandlers; + }); +define("htmlbars-compiler/html-parser/tokens", + ["../../simple-html-tokenizer","../ast","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Chars = __dependency1__.Chars; + var StartTag = __dependency1__.StartTag; + var EndTag = __dependency1__.EndTag; + var AttrNode = __dependency2__.AttrNode; + var TextNode = __dependency2__.TextNode; + var MustacheNode = __dependency2__.MustacheNode; + var StringNode = __dependency2__.StringNode; + var IdNode = __dependency2__.IdNode; + + StartTag.prototype.startAttribute = function(char) { + this.finalizeAttributeValue(); + this.currentAttribute = new AttrNode(char.toLowerCase(), []); + this.attributes.push(this.currentAttribute); + }; + + StartTag.prototype.addToAttributeName = function(char) { + this.currentAttribute.name += char; + }; + + StartTag.prototype.addToAttributeValue = function(char) { + var value = this.currentAttribute.value; + + if (char.type === 'mustache') { + value.push(char); + } else { + if (value.length > 0 && value[value.length - 1].type === 'text') { + value[value.length - 1].chars += char; + } else { + value.push(new TextNode(char)); + } + } + }; + + StartTag.prototype.finalize = function() { + this.finalizeAttributeValue(); + delete this.currentAttribute; + return this; + }; + + StartTag.prototype.finalizeAttributeValue = function() { + var attr = this.currentAttribute; + + if (!attr) return; + + if (attr.value.length === 1) { + // Unwrap a single TextNode or MustacheNode + attr.value = attr.value[0]; + } else { + // If the attr value has multiple parts combine them into + // a single MustacheNode with the concat helper + var params = [ new IdNode([{ part: 'concat' }]) ]; + + for (var i = 0; i < attr.value.length; i++) { + var part = attr.value[i]; + if (part.type === 'text') { + params.push(new StringNode(part.chars)); + } else if (part.type === 'mustache') { + var sexpr = part.sexpr; + delete sexpr.isRoot; + + if (sexpr.isHelper) { + sexpr.isHelper = true; + } + + params.push(sexpr); + } + } + + attr.value = new MustacheNode(params, undefined, true, { left: false, right: false }); + } + }; + + StartTag.prototype.addTagHelper = function(helper) { + var helpers = this.helpers = this.helpers || []; + helpers.push(helper); + }; + + __exports__.Chars = Chars; + __exports__.StartTag = StartTag; + __exports__.EndTag = EndTag; + }); +define("htmlbars-compiler/parser", + ["../handlebars/compiler/base","../simple-html-tokenizer","./html-parser/node-handlers","./html-parser/token-handlers","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var parse = __dependency1__.parse; + var Tokenizer = __dependency2__.Tokenizer; + var nodeHandlers = __dependency3__["default"]; + var tokenHandlers = __dependency4__["default"]; + + function preprocess(html, options) { + var ast = parse(html); + var combined = new HTMLProcessor().acceptNode(ast); + return combined; + } + + __exports__.preprocess = preprocess;function HTMLProcessor() { + this.elementStack = []; + this.tokenizer = new Tokenizer(''); + this.nodeHandlers = nodeHandlers; + this.tokenHandlers = tokenHandlers; + } + + HTMLProcessor.prototype.acceptNode = function(node) { + return this.nodeHandlers[node.type].call(this, node); + }; + + HTMLProcessor.prototype.acceptToken = function(token) { + if (token) { + return this.tokenHandlers[token.type].call(this, token); + } + }; + + HTMLProcessor.prototype.currentElement = function() { + return this.elementStack[this.elementStack.length - 1]; + }; + }); +define("htmlbars-compiler/utils", + ["exports"], + function(__exports__) { + "use strict"; + function forEach(array, callback, binding) { + var i, l; + if (binding === undefined) { + for (i=0, l=array.length; i + //
+ // + // + // The tbody may be omitted, and the browser will accept and render: + // + //
+ // + // + // However, the omitted start tag will still be added to the DOM. Here + // we test the string and context to see if the browser is about to + // perform this cleanup. + // + // http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#optional-tags + // describes which tags are omittable. The spec for tbody and colgroup + // explains this behavior: + // + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-tbody-element + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-colgroup-element + // + + var omittedStartTagChildTest = /<([\w:]+)/; + function detectOmittedStartTag(string, contextualElement){ + // Omitted start tags are only inside table tags. + if (contextualElement.tagName === 'TABLE') { + var omittedStartTagChildMatch = omittedStartTagChildTest.exec(string); + if (omittedStartTagChildMatch) { + var omittedStartTagChild = omittedStartTagChildMatch[1]; + // It is already asserted that the contextual element is a table + // and not the proper start tag. Just see if a tag was omitted. + return omittedStartTagChild === 'tr' || + omittedStartTagChild === 'col'; + } + } + } + + function buildSVGDOM(html, dom){ + var div = dom.document.createElement('div'); + div.innerHTML = ''+html+''; + return div.firstChild.childNodes; + } + + /* + * A class wrapping DOM functions to address environment compatibility, + * namespaces, contextual elements for morph un-escaped content + * insertion. + * + * When entering a template, a DOMHelper should be passed: + * + * template(context, { hooks: hooks, dom: new DOMHelper() }); + * + * TODO: support foreignObject as a passed contextual element. It has + * a namespace (svg) that does not match its internal namespace + * (xhtml). + * + * @class DOMHelper + * @constructor + * @param {HTMLDocument} _document The document DOM methods are proxied to + */ + function DOMHelper(_document){ + this.document = _document || window.document; + this.namespace = null; + } + + var prototype = DOMHelper.prototype; + prototype.constructor = DOMHelper; + + prototype.insertBefore = function(element, childElement, referenceChild) { + return element.insertBefore(childElement, referenceChild); + }; + + prototype.appendChild = function(element, childElement) { + return element.appendChild(childElement); + }; + + prototype.appendText = function(element, text) { + return element.appendChild(this.document.createTextNode(text)); + }; + + prototype.setAttribute = function(element, name, value) { + element.setAttribute(name, value); + }; + + if (document.createElementNS) { + // Only opt into namespace detection if a contextualElement + // is passed. + prototype.createElement = function(tagName, contextualElement) { + var namespace = this.namespace; + if (contextualElement) { + if (tagName === 'svg') { + namespace = svgNamespace; + } else { + namespace = interiorNamespace(contextualElement); + } + } + if (namespace) { + return this.document.createElementNS(namespace, tagName); + } else { + return this.document.createElement(tagName); + } + }; + } else { + prototype.createElement = function(tagName) { + return this.document.createElement(tagName); + }; + } + + prototype.setNamespace = function(ns) { + this.namespace = ns; + }; + + prototype.detectNamespace = function(element) { + this.namespace = interiorNamespace(element); + }; + + prototype.createDocumentFragment = function(){ + return this.document.createDocumentFragment(); + }; + + prototype.createTextNode = function(text){ + return this.document.createTextNode(text); + }; + + prototype.repairClonedNode = function(element, blankChildTextNodes, isChecked){ + if (deletesBlankTextNodes && blankChildTextNodes.length > 0) { + for (var i=0, len=blankChildTextNodes.length;i]*)>", 'i'))[0]; + var endTag = ''; + + var wrappedHTML = [startTag, html, endTag]; + + var i = wrappingTags.length; + var wrappedDepth = 1 + i; + while(i--) { + wrappedHTML.unshift('<'+wrappingTags[i]+'>'); + wrappedHTML.push(''); + } + + var wrapper = document.createElement('div'); + scriptSafeInnerHTML(wrapper, wrappedHTML.join('')); + var element = wrapper; + while (wrappedDepth--) { + element = element.firstChild; + while (element && element.nodeType !== 1) { + element = element.nextSibling; + } + } + while (element && element.tagName !== tagName) { + element = element.nextSibling; + } + return element ? element.childNodes : []; + } + + var buildDOM; + if (needsShy) { + buildDOM = function buildDOM(html, contextualElement, dom){ + contextualElement = dom.cloneNode(contextualElement, false); + scriptSafeInnerHTML(contextualElement, html); + return contextualElement.childNodes; + }; + } else { + buildDOM = function buildDOM(html, contextualElement, dom){ + contextualElement = dom.cloneNode(contextualElement, false); + contextualElement.innerHTML = html; + return contextualElement.childNodes; + }; + } + + + var buildIESafeDOM; + if (tagNamesRequiringInnerHTMLFix.length > 0 || movesWhitespace) { + buildIESafeDOM = function buildIESafeDOM(html, contextualElement, dom) { + // Make a list of the leading text on script nodes. Include + // script tags without any whitespace for easier processing later. + var spacesBefore = []; + var spacesAfter = []; + html = html.replace(/(\s*)()(\s*)/g, function(match, tag, spaces) { + spacesAfter.push(spaces); + return tag; + }); + + // Fetch nodes + var nodes; + if (tagNamesRequiringInnerHTMLFix[contextualElement.tagName.toLowerCase()]) { + // buildDOMWithFix uses string wrappers for problematic innerHTML. + nodes = buildDOMWithFix(html, contextualElement); + } else { + nodes = buildDOM(html, contextualElement, dom); + } + + // Build a list of script tags, the nodes themselves will be + // mutated as we add test nodes. + var i, j, node, nodeScriptNodes; + var scriptNodes = []; + for (i=0;node=nodes[i];i++) { + if (node.nodeType !== 1) { + continue; + } + if (node.tagName === 'SCRIPT') { + scriptNodes.push(node); + } else { + nodeScriptNodes = node.getElementsByTagName('script'); + for (j=0;j 0) { + textNode = dom.document.createTextNode(spaceBefore); + scriptNode.parentNode.insertBefore(textNode, scriptNode); + } + + spaceAfter = spacesAfter[i]; + if (spaceAfter && spaceAfter.length > 0) { + textNode = dom.document.createTextNode(spaceAfter); + scriptNode.parentNode.insertBefore(textNode, scriptNode.nextSibling); + } + } + + return nodes; + }; + } else { + buildIESafeDOM = buildDOM; + } + + var buildHTMLDOM; + if (needsIntegrationPointFix) { + buildHTMLDOM = function buildHTMLDOM(html, contextualElement, dom){ + if (svgHTMLIntegrationPoints[contextualElement.tagName]) { + return buildIESafeDOM(html, document.createElement('div'), dom); + } else { + return buildIESafeDOM(html, contextualElement, dom); + } + }; + } else { + buildHTMLDOM = buildIESafeDOM; + } + + __exports__.buildHTMLDOM = buildHTMLDOM; + }); +define("morph/morph", + ["exports"], + function(__exports__) { + "use strict"; + var splice = Array.prototype.splice; + + function ensureStartEnd(start, end) { + if (start === null || end === null) { + throw new Error('a fragment parent must have boundary nodes in order to detect insertion'); + } + } + + function ensureContext(contextualElement) { + if (!contextualElement || contextualElement.nodeType !== 1) { + throw new Error('An element node must be provided for a contextualElement, you provided ' + + (contextualElement ? 'nodeType ' + contextualElement.nodeType : 'nothing')); + } + } + + // TODO: this is an internal API, this should be an assert + function Morph(parent, start, end, domHelper, contextualElement) { + if (parent.nodeType === 11) { + ensureStartEnd(start, end); + this.element = null; + } else { + this.element = parent; + } + this._parent = parent; + this.start = start; + this.end = end; + this.domHelper = domHelper; + ensureContext(contextualElement); + this.contextualElement = contextualElement; + this.reset(); + } + + Morph.prototype.reset = function() { + this.text = null; + this.owner = null; + this.morphs = null; + this.before = null; + this.after = null; + this.escaped = true; + }; + + Morph.prototype.parent = function () { + if (!this.element) { + var parent = this.start.parentNode; + if (this._parent !== parent) { + this.element = this._parent = parent; + } + } + return this._parent; + }; + + Morph.prototype.destroy = function () { + if (this.owner) { + this.owner.removeMorph(this); + } else { + clear(this.element || this.parent(), this.start, this.end); + } + }; + + Morph.prototype.removeMorph = function (morph) { + var morphs = this.morphs; + for (var i=0, l=morphs.length; i 0 ? morphs[index-1] : null; + var after = index < morphs.length ? morphs[index] : null; + var start = before === null ? this.start : (before.end === null ? parent.lastChild : before.end.previousSibling); + var end = after === null ? this.end : (after.start === null ? parent.firstChild : after.start.nextSibling); + var morph = new Morph(parent, start, end, this.domHelper, this.contextualElement); + + morph.owner = this; + morph._update(parent, node); + + if (before !== null) { + morph.before = before; + before.end = start.nextSibling; + before.after = morph; + } + + if (after !== null) { + morph.after = after; + after.before = morph; + after.start = end.previousSibling; + } + + this.morphs.splice(index, 0, morph); + return morph; + }; + + Morph.prototype.replace = function (index, removedLength, addedNodes) { + if (this.morphs === null) this.morphs = []; + var parent = this.element || this.parent(); + var morphs = this.morphs; + var before = index > 0 ? morphs[index-1] : null; + var after = index+removedLength < morphs.length ? morphs[index+removedLength] : null; + var start = before === null ? this.start : (before.end === null ? parent.lastChild : before.end.previousSibling); + var end = after === null ? this.end : (after.start === null ? parent.firstChild : after.start.nextSibling); + var addedLength = addedNodes === undefined ? 0 : addedNodes.length; + var args, i, current; + + if (removedLength > 0) { + clear(parent, start, end); + } + + if (addedLength === 0) { + if (before !== null) { + before.after = after; + before.end = end; + } + if (after !== null) { + after.before = before; + after.start = start; + } + morphs.splice(index, removedLength); + return; + } + + args = new Array(addedLength+2); + if (addedLength > 0) { + for (i=0; i") { + return this.emitToken(); + } else { + this.addToComment(char); + this.state = 'comment'; + } + }, + + commentStartDash: function(char) { + if (char === "-") { + this.state = 'commentEnd'; + } else if (char === ">") { + return this.emitToken(); + } else { + this.addToComment("-"); + this.state = 'comment'; + } + }, + + comment: function(char) { + if (char === "-") { + this.state = 'commentEndDash'; + } else { + this.addToComment(char); + } + }, + + commentEndDash: function(char) { + if (char === "-") { + this.state = 'commentEnd'; + } else { + this.addToComment("-" + char); + this.state = 'comment'; + } + }, + + commentEnd: function(char) { + if (char === ">") { + return this.emitToken(); + } else { + this.addToComment("--" + char); + this.state = 'comment'; + } + }, + + tagName: function(char) { + if (isSpace(char)) { + this.state = 'beforeAttributeName'; + } else if (char === "/") { + this.state = 'selfClosingStartTag'; + } else if (char === ">") { + return this.emitToken(); + } else { + this.token.addToTagName(char); + } + }, + + beforeAttributeName: function(char) { + if (isSpace(char)) { + return; + } else if (char === "/") { + this.state = 'selfClosingStartTag'; + } else if (char === ">") { + return this.emitToken(); + } else { + this.attribute(char); + } + }, + + attributeName: function(char) { + if (isSpace(char)) { + this.state = 'afterAttributeName'; + } else if (char === "/") { + this.state = 'selfClosingStartTag'; + } else if (char === "=") { + this.state = 'beforeAttributeValue'; + } else if (char === ">") { + return this.emitToken(); + } else { + this.addToAttributeName(char); + } + }, + + afterAttributeName: function(char) { + if (isSpace(char)) { + return; + } else if (char === "/") { + this.state = 'selfClosingStartTag'; + } else if (char === "=") { + this.state = 'beforeAttributeValue'; + } else if (char === ">") { + return this.emitToken(); + } else { + this.attribute(char); + } + }, + + beforeAttributeValue: function(char) { + if (isSpace(char)) { + return; + } else if (char === '"') { + this.state = 'attributeValueDoubleQuoted'; + } else if (char === "'") { + this.state = 'attributeValueSingleQuoted'; + } else if (char === ">") { + return this.emitToken(); + } else { + this.state = 'attributeValueUnquoted'; + this.addToAttributeValue(char); + } + }, + + attributeValueDoubleQuoted: function(char) { + if (char === '"') { + this.state = 'afterAttributeValueQuoted'; + } else if (char === "&") { + this.addToAttributeValue(this.consumeCharRef('"') || "&"); + } else { + this.addToAttributeValue(char); + } + }, + + attributeValueSingleQuoted: function(char) { + if (char === "'") { + this.state = 'afterAttributeValueQuoted'; + } else if (char === "&") { + this.addToAttributeValue(this.consumeCharRef("'") || "&"); + } else { + this.addToAttributeValue(char); + } + }, + + attributeValueUnquoted: function(char) { + if (isSpace(char)) { + this.state = 'beforeAttributeName'; + } else if (char === "&") { + this.addToAttributeValue(this.consumeCharRef(">") || "&"); + } else if (char === ">") { + return this.emitToken(); + } else { + this.addToAttributeValue(char); + } + }, + + afterAttributeValueQuoted: function(char) { + if (isSpace(char)) { + this.state = 'beforeAttributeName'; + } else if (char === "/") { + this.state = 'selfClosingStartTag'; + } else if (char === ">") { + return this.emitToken(); + } else { + this.char--; + this.state = 'beforeAttributeName'; + } + }, + + selfClosingStartTag: function(char) { + if (char === ">") { + this.selfClosing(); + return this.emitToken(); + } else { + this.char--; + this.state = 'beforeAttributeName'; + } + }, + + endTagOpen: function(char) { + if (isAlpha(char)) { + this.tag(EndTag, char.toLowerCase()); + } + } + } + }; + + function Tag(tagName, attributes, options) { + this.tagName = tagName || ""; + this.attributes = attributes || []; + this.selfClosing = options ? options.selfClosing : false; + } + + Tag.prototype = { + constructor: Tag, + + addToTagName: function(char) { + this.tagName += char; + }, + + startAttribute: function(char) { + this.currentAttribute = [char.toLowerCase(), null]; + this.attributes.push(this.currentAttribute); + }, + + addToAttributeName: function(char) { + this.currentAttribute[0] += char; + }, + + addToAttributeValue: function(char) { + this.currentAttribute[1] = this.currentAttribute[1] || ""; + this.currentAttribute[1] += char; + }, + + finalize: function() { + delete this.currentAttribute; + return this; + } + }; + + function StartTag() { + Tag.apply(this, arguments); + } + + StartTag.prototype = objectCreate(Tag.prototype); + StartTag.prototype.type = 'StartTag'; + StartTag.prototype.constructor = StartTag; + + StartTag.prototype.toHTML = function() { + return config.generateTag(this); + }; + + function generateTag(tag) { + var out = "<"; + out += tag.tagName; + + if (tag.attributes.length) { + out += " " + config.generateAttributes(tag.attributes); + } + + out += ">"; + + return out; + } + + function generateAttributes(attributes) { + var out = [], attribute, attrString, value; + + for (var i=0, l=attributes.length; i"; + } + }; + + function tokenize(input) { + var tokenizer = new Tokenizer(input); + return tokenizer.tokenize(); + } + + function generate(tokens) { + var output = ""; + + for (var i=0, l=tokens.length; i + // + // + // + // The tbody may be omitted, and the browser will accept and render: + // + //
+ // + // + // However, the omitted start tag will still be added to the DOM. Here + // we test the string and context to see if the browser is about to + // perform this cleanup. + // + // http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#optional-tags + // describes which tags are omittable. The spec for tbody and colgroup + // explains this behavior: + // + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-tbody-element + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-colgroup-element + // + + var omittedStartTagChildTest = /<([\w:]+)/; + function detectOmittedStartTag(string, contextualElement){ + // Omitted start tags are only inside table tags. + if (contextualElement.tagName === 'TABLE') { + var omittedStartTagChildMatch = omittedStartTagChildTest.exec(string); + if (omittedStartTagChildMatch) { + var omittedStartTagChild = omittedStartTagChildMatch[1]; + // It is already asserted that the contextual element is a table + // and not the proper start tag. Just see if a tag was omitted. + return omittedStartTagChild === 'tr' || + omittedStartTagChild === 'col'; + } + } + } + + function buildSVGDOM(html, dom){ + var div = dom.document.createElement('div'); + div.innerHTML = ''+html+''; + return div.firstChild.childNodes; + } + + /* + * A class wrapping DOM functions to address environment compatibility, + * namespaces, contextual elements for morph un-escaped content + * insertion. + * + * When entering a template, a DOMHelper should be passed: + * + * template(context, { hooks: hooks, dom: new DOMHelper() }); + * + * TODO: support foreignObject as a passed contextual element. It has + * a namespace (svg) that does not match its internal namespace + * (xhtml). + * + * @class DOMHelper + * @constructor + * @param {HTMLDocument} _document The document DOM methods are proxied to + */ + function DOMHelper(_document){ + this.document = _document || window.document; + this.namespace = null; + } + + var prototype = DOMHelper.prototype; + prototype.constructor = DOMHelper; + + prototype.insertBefore = function(element, childElement, referenceChild) { + return element.insertBefore(childElement, referenceChild); + }; + + prototype.appendChild = function(element, childElement) { + return element.appendChild(childElement); + }; + + prototype.appendText = function(element, text) { + return element.appendChild(this.document.createTextNode(text)); + }; + + prototype.setAttribute = function(element, name, value) { + element.setAttribute(name, value); + }; + + if (document.createElementNS) { + // Only opt into namespace detection if a contextualElement + // is passed. + prototype.createElement = function(tagName, contextualElement) { + var namespace = this.namespace; + if (contextualElement) { + if (tagName === 'svg') { + namespace = svgNamespace; + } else { + namespace = interiorNamespace(contextualElement); + } + } + if (namespace) { + return this.document.createElementNS(namespace, tagName); + } else { + return this.document.createElement(tagName); + } + }; + } else { + prototype.createElement = function(tagName) { + return this.document.createElement(tagName); + }; + } + + prototype.setNamespace = function(ns) { + this.namespace = ns; + }; + + prototype.detectNamespace = function(element) { + this.namespace = interiorNamespace(element); + }; + + prototype.createDocumentFragment = function(){ + return this.document.createDocumentFragment(); + }; + + prototype.createTextNode = function(text){ + return this.document.createTextNode(text); + }; + + prototype.repairClonedNode = function(element, blankChildTextNodes, isChecked){ + if (deletesBlankTextNodes && blankChildTextNodes.length > 0) { + for (var i=0, len=blankChildTextNodes.length;i]*)>", 'i'))[0]; + var endTag = ''; + + var wrappedHTML = [startTag, html, endTag]; + + var i = wrappingTags.length; + var wrappedDepth = 1 + i; + while(i--) { + wrappedHTML.unshift('<'+wrappingTags[i]+'>'); + wrappedHTML.push(''); + } + + var wrapper = document.createElement('div'); + scriptSafeInnerHTML(wrapper, wrappedHTML.join('')); + var element = wrapper; + while (wrappedDepth--) { + element = element.firstChild; + while (element && element.nodeType !== 1) { + element = element.nextSibling; + } + } + while (element && element.tagName !== tagName) { + element = element.nextSibling; + } + return element ? element.childNodes : []; + } + + var buildDOM; + if (needsShy) { + buildDOM = function buildDOM(html, contextualElement, dom){ + contextualElement = dom.cloneNode(contextualElement, false); + scriptSafeInnerHTML(contextualElement, html); + return contextualElement.childNodes; + }; + } else { + buildDOM = function buildDOM(html, contextualElement, dom){ + contextualElement = dom.cloneNode(contextualElement, false); + contextualElement.innerHTML = html; + return contextualElement.childNodes; + }; + } + + + var buildIESafeDOM; + if (tagNamesRequiringInnerHTMLFix.length > 0 || movesWhitespace) { + buildIESafeDOM = function buildIESafeDOM(html, contextualElement, dom) { + // Make a list of the leading text on script nodes. Include + // script tags without any whitespace for easier processing later. + var spacesBefore = []; + var spacesAfter = []; + html = html.replace(/(\s*)()(\s*)/g, function(match, tag, spaces) { + spacesAfter.push(spaces); + return tag; + }); + + // Fetch nodes + var nodes; + if (tagNamesRequiringInnerHTMLFix[contextualElement.tagName.toLowerCase()]) { + // buildDOMWithFix uses string wrappers for problematic innerHTML. + nodes = buildDOMWithFix(html, contextualElement); + } else { + nodes = buildDOM(html, contextualElement, dom); + } + + // Build a list of script tags, the nodes themselves will be + // mutated as we add test nodes. + var i, j, node, nodeScriptNodes; + var scriptNodes = []; + for (i=0;node=nodes[i];i++) { + if (node.nodeType !== 1) { + continue; + } + if (node.tagName === 'SCRIPT') { + scriptNodes.push(node); + } else { + nodeScriptNodes = node.getElementsByTagName('script'); + for (j=0;j 0) { + textNode = dom.document.createTextNode(spaceBefore); + scriptNode.parentNode.insertBefore(textNode, scriptNode); + } + + spaceAfter = spacesAfter[i]; + if (spaceAfter && spaceAfter.length > 0) { + textNode = dom.document.createTextNode(spaceAfter); + scriptNode.parentNode.insertBefore(textNode, scriptNode.nextSibling); + } + } + + return nodes; + }; + } else { + buildIESafeDOM = buildDOM; + } + + var buildHTMLDOM; + if (needsIntegrationPointFix) { + buildHTMLDOM = function buildHTMLDOM(html, contextualElement, dom){ + if (svgHTMLIntegrationPoints[contextualElement.tagName]) { + return buildIESafeDOM(html, document.createElement('div'), dom); + } else { + return buildIESafeDOM(html, contextualElement, dom); + } + }; + } else { + buildHTMLDOM = buildIESafeDOM; + } + + __exports__.buildHTMLDOM = buildHTMLDOM; + }); +define("morph/morph", + ["exports"], + function(__exports__) { + "use strict"; + var splice = Array.prototype.splice; + + function ensureStartEnd(start, end) { + if (start === null || end === null) { + throw new Error('a fragment parent must have boundary nodes in order to detect insertion'); + } + } + + function ensureContext(contextualElement) { + if (!contextualElement || contextualElement.nodeType !== 1) { + throw new Error('An element node must be provided for a contextualElement, you provided ' + + (contextualElement ? 'nodeType ' + contextualElement.nodeType : 'nothing')); + } + } + + // TODO: this is an internal API, this should be an assert + function Morph(parent, start, end, domHelper, contextualElement) { + if (parent.nodeType === 11) { + ensureStartEnd(start, end); + this.element = null; + } else { + this.element = parent; + } + this._parent = parent; + this.start = start; + this.end = end; + this.domHelper = domHelper; + ensureContext(contextualElement); + this.contextualElement = contextualElement; + this.reset(); + } + + Morph.prototype.reset = function() { + this.text = null; + this.owner = null; + this.morphs = null; + this.before = null; + this.after = null; + this.escaped = true; + }; + + Morph.prototype.parent = function () { + if (!this.element) { + var parent = this.start.parentNode; + if (this._parent !== parent) { + this.element = this._parent = parent; + } + } + return this._parent; + }; + + Morph.prototype.destroy = function () { + if (this.owner) { + this.owner.removeMorph(this); + } else { + clear(this.element || this.parent(), this.start, this.end); + } + }; + + Morph.prototype.removeMorph = function (morph) { + var morphs = this.morphs; + for (var i=0, l=morphs.length; i 0 ? morphs[index-1] : null; + var after = index < morphs.length ? morphs[index] : null; + var start = before === null ? this.start : (before.end === null ? parent.lastChild : before.end.previousSibling); + var end = after === null ? this.end : (after.start === null ? parent.firstChild : after.start.nextSibling); + var morph = new Morph(parent, start, end, this.domHelper, this.contextualElement); + + morph.owner = this; + morph._update(parent, node); + + if (before !== null) { + morph.before = before; + before.end = start.nextSibling; + before.after = morph; + } + + if (after !== null) { + morph.after = after; + after.before = morph; + after.start = end.previousSibling; + } + + this.morphs.splice(index, 0, morph); + return morph; + }; + + Morph.prototype.replace = function (index, removedLength, addedNodes) { + if (this.morphs === null) this.morphs = []; + var parent = this.element || this.parent(); + var morphs = this.morphs; + var before = index > 0 ? morphs[index-1] : null; + var after = index+removedLength < morphs.length ? morphs[index+removedLength] : null; + var start = before === null ? this.start : (before.end === null ? parent.lastChild : before.end.previousSibling); + var end = after === null ? this.end : (after.start === null ? parent.firstChild : after.start.nextSibling); + var addedLength = addedNodes === undefined ? 0 : addedNodes.length; + var args, i, current; + + if (removedLength > 0) { + clear(parent, start, end); + } + + if (addedLength === 0) { + if (before !== null) { + before.after = after; + before.end = end; + } + if (after !== null) { + after.before = before; + after.start = start; + } + morphs.splice(index, removedLength); + return; + } + + args = new Array(addedLength+2); + if (addedLength > 0) { + for (i=0; i") { + return this.emitToken(); + } else { + this.addToComment(char); + this.state = 'comment'; + } + }, + + commentStartDash: function(char) { + if (char === "-") { + this.state = 'commentEnd'; + } else if (char === ">") { + return this.emitToken(); + } else { + this.addToComment("-"); + this.state = 'comment'; + } + }, + + comment: function(char) { + if (char === "-") { + this.state = 'commentEndDash'; + } else { + this.addToComment(char); + } + }, + + commentEndDash: function(char) { + if (char === "-") { + this.state = 'commentEnd'; + } else { + this.addToComment("-" + char); + this.state = 'comment'; + } + }, + + commentEnd: function(char) { + if (char === ">") { + return this.emitToken(); + } else { + this.addToComment("--" + char); + this.state = 'comment'; + } + }, + + tagName: function(char) { + if (isSpace(char)) { + this.state = 'beforeAttributeName'; + } else if (char === "/") { + this.state = 'selfClosingStartTag'; + } else if (char === ">") { + return this.emitToken(); + } else { + this.token.addToTagName(char); + } + }, + + beforeAttributeName: function(char) { + if (isSpace(char)) { + return; + } else if (char === "/") { + this.state = 'selfClosingStartTag'; + } else if (char === ">") { + return this.emitToken(); + } else { + this.attribute(char); + } + }, + + attributeName: function(char) { + if (isSpace(char)) { + this.state = 'afterAttributeName'; + } else if (char === "/") { + this.state = 'selfClosingStartTag'; + } else if (char === "=") { + this.state = 'beforeAttributeValue'; + } else if (char === ">") { + return this.emitToken(); + } else { + this.addToAttributeName(char); + } + }, + + afterAttributeName: function(char) { + if (isSpace(char)) { + return; + } else if (char === "/") { + this.state = 'selfClosingStartTag'; + } else if (char === "=") { + this.state = 'beforeAttributeValue'; + } else if (char === ">") { + return this.emitToken(); + } else { + this.attribute(char); + } + }, + + beforeAttributeValue: function(char) { + if (isSpace(char)) { + return; + } else if (char === '"') { + this.state = 'attributeValueDoubleQuoted'; + } else if (char === "'") { + this.state = 'attributeValueSingleQuoted'; + } else if (char === ">") { + return this.emitToken(); + } else { + this.state = 'attributeValueUnquoted'; + this.addToAttributeValue(char); + } + }, + + attributeValueDoubleQuoted: function(char) { + if (char === '"') { + this.state = 'afterAttributeValueQuoted'; + } else if (char === "&") { + this.addToAttributeValue(this.consumeCharRef('"') || "&"); + } else { + this.addToAttributeValue(char); + } + }, + + attributeValueSingleQuoted: function(char) { + if (char === "'") { + this.state = 'afterAttributeValueQuoted'; + } else if (char === "&") { + this.addToAttributeValue(this.consumeCharRef("'") || "&"); + } else { + this.addToAttributeValue(char); + } + }, + + attributeValueUnquoted: function(char) { + if (isSpace(char)) { + this.state = 'beforeAttributeName'; + } else if (char === "&") { + this.addToAttributeValue(this.consumeCharRef(">") || "&"); + } else if (char === ">") { + return this.emitToken(); + } else { + this.addToAttributeValue(char); + } + }, + + afterAttributeValueQuoted: function(char) { + if (isSpace(char)) { + this.state = 'beforeAttributeName'; + } else if (char === "/") { + this.state = 'selfClosingStartTag'; + } else if (char === ">") { + return this.emitToken(); + } else { + this.char--; + this.state = 'beforeAttributeName'; + } + }, + + selfClosingStartTag: function(char) { + if (char === ">") { + this.selfClosing(); + return this.emitToken(); + } else { + this.char--; + this.state = 'beforeAttributeName'; + } + }, + + endTagOpen: function(char) { + if (isAlpha(char)) { + this.tag(EndTag, char.toLowerCase()); + } + } + } +}; + +function Tag(tagName, attributes, options) { + this.tagName = tagName || ""; + this.attributes = attributes || []; + this.selfClosing = options ? options.selfClosing : false; +} + +Tag.prototype = { + constructor: Tag, + + addToTagName: function(char) { + this.tagName += char; + }, + + startAttribute: function(char) { + this.currentAttribute = [char.toLowerCase(), null]; + this.attributes.push(this.currentAttribute); + }, + + addToAttributeName: function(char) { + this.currentAttribute[0] += char; + }, + + addToAttributeValue: function(char) { + this.currentAttribute[1] = this.currentAttribute[1] || ""; + this.currentAttribute[1] += char; + }, + + finalize: function() { + delete this.currentAttribute; + return this; + } +}; + +function StartTag() { + Tag.apply(this, arguments); +} + +StartTag.prototype = objectCreate(Tag.prototype); +StartTag.prototype.type = 'StartTag'; +StartTag.prototype.constructor = StartTag; + +StartTag.prototype.toHTML = function() { + return config.generateTag(this); +}; + +function generateTag(tag) { + var out = "<"; + out += tag.tagName; + + if (tag.attributes.length) { + out += " " + config.generateAttributes(tag.attributes); + } + + out += ">"; + + return out; +} + +function generateAttributes(attributes) { + var out = [], attribute, attrString, value; + + for (var i=0, l=attributes.length; i"; + } +}; + +function tokenize(input) { + var tokenizer = new Tokenizer(input); + return tokenizer.tokenize(); +} + +function generate(tokens) { + var output = ""; + + for (var i=0, l=tokens.length; i,accent,slide,gate,down,up] + //this.pattern = [ + //[40,true,false,true,false,false], + //[40,false,true,true,false,false], + //[40,false,true,true,false,false], + //[40,false,true,true,false,false], + //[40,false,false,true,false,false], + //[40,false,true,true,false,false], + //[40,true,true,true,false,false], + //[40,false,true,true,false,false], + //[40,false,false,true,false,false], + //[47,true,false,true,false,false], + //[42,false,false,true,false,false], + //[48,true,false,true,false,false], + //[43,false,false,true,false,false], + //[50,false,false,true,false,false], + //[50,true,true,true,true,false], + //[50,false,true,true,true,false] + //]; + + // serialization functions + this.serialize = function() { + return [ + this.pattern, + this.tempo, + this.tuning, + this.waveform, + this.cutoff, + this.resonance, + this.envmod, + this.decay, + this.accent, + this.dist_shape, + this.dist_threshold, + this.delay_feedback, + this.delay_send, + this.delay_length + ]; + }; + + this.unserialize = function(o) { + this.pattern=o[0].slice(0); + this.settempo(o[1]); + this.tuning=o[2]; + this.waveform=o[3]; + this.envmod=o[6]; + this.setresonance(o[5]); + this.setcutoff(o[4]); + this.decay=o[7]; + this.accent=o[8]; + this.dist_shape=o[9]; + this.setdistthreshold(o[10]); + this.delay_feedback=o[11]; + this.delay_send=o[12]; + this.delay_length=o[13]; + }; + + // sound parameter setters + this.settempo = function(newtempo) { + this.tempo = newtempo; + this.steplength = samplerate * 60.0 / this.tempo / 4.0; + }; + + this.setdistthreshold = function(newthresh) { + // TODO: this destroys threshold value + this.dist_threshold = newthresh + this.effective_dist_threshold = 1.0 - 0.9 * this.dist_threshold; + this.dist_gain = 1.0 / this.effective_dist_threshold; + }; + + this.setcutoff = function(newcutoff) { + this.cutoff = newcutoff; + this.setenvmod(this.envmod); + }; + + this.setresonance = function(newresonance) { + this.resonance = newresonance; + this.resonance_skewed = (1.0 - Math.exp(-3.0 * this.resonance)) / (1.0 - Math.exp(-3.0)); + }; + + this.setenvmod = function(newenvmod) { + this.envmod = newenvmod; + + var c0 = 3.138152786059267e+2; + var c1 = 2.394411986817546e+3; + var c = Math.log(this.cutoff / c0) / Math.log(c1 / c0); + + var slo = 3.773996325111173 * this.envmod + 0.736965594166206; + var shi = 4.194548788411135 * this.envmod + 0.864344900642434; + + this.envscaler = (1.0 - c) * slo + c * shi; + this.envoffset = 0.048292930943553 * c + 0.294391201442418; + }; + + // reset/initialize everything + this.reset = function() { + this.onepole = [ + coeff_highpass(44.486), + coeff_highpass(150.0), + coeff_allpass(14.008), + coeff_highpass(24.167) + ]; + + this.biquad = [ + coeff_biquad_lowpass12db(200.0, Math.sqrt(0.5)), + coeff_biquad_notch(7.5164, 4.7) + ]; + + this.tbfilter = [0, 0, 0, 0, 0]; // [y0,y1,y2,y3,y4] + + this.settempo(this.tempo); + this.setdistthreshold(this.dist_threshold); + this.setresonance(this.resonance); + this.setenvmod(this.envmod); + + this.samplepos = 1000000; + this.pos = -1; + this.oscpos = 0.0; + }; + + // renderer + this.render = function() { + var anti_denormal = 1.0e-20; + + if (this.running) { + // Step sequencer + if ((++this.samplepos) >= this.steplength) { + // Advance sequencer + this.samplepos = 0; + this.pos++ + + // Advance pattern if we reached the end + if (this.pos >= this.pattern.numberOfSteps) { + this.pos = 0 + this.pattern = this.nextPattern + } + + // Trigger step change callback + this.onStepChanged() + + // Calculate target pitch + var step = this.pattern.steps[this.pos]; + var pitch = step.pitch - step.down * 12 + step.up * 12 + this.tuning; + var f = 440.0 * Math.pow(2.0, (pitch - 69.0) / 12.0); + + // Decay multiplier + this.ampmult = Math.exp(-1.0 / (0.001 * this.decay * samplerate)); + if (step.accent) { // if accent + this.filtermult = Math.exp(-1.0 / (0.001 *200 * samplerate)); + this.accentgain = this.accent; + } else { + this.filtermult = this.ampmult; + this.accentgain = 0.0; + } + this.ampenv = (1.0 / this.ampmult) * step.gate; + + // VCO parameters + if (step.slide) { // if slide + // TODO: set up leaky integrator for slide motion + this.slide = (this.oscdelta -(f * 4096.0 / samplerate)) / 64.0; + this.slidestep = 0; + } else { + this.filterenv = 1.0 / this.filtermult; + this.oscpos = 0.0; + this.slide = 0.0; + this.slidestep = 64; + this.oscdelta = f * 4096.0 / samplerate; + this.table = this.waveform * 524288 + (step.pitch << 12); + } + } + } else { + this.ampenv = 0.0; + } + + // Envelopes + this.ampenv = this.ampenv * this.ampmult + anti_denormal; + this.filterenv = this.filterenv * this.filtermult + anti_denormal; + + // VCO + var idx = Math.round(this.oscpos); + var r = this.oscpos - idx; + var sample = ((1.0 - r) * wavetable[this.table + idx] + r * wavetable[this.table + ((idx + 1) & 4095)]); + this.oscpos += this.oscdelta; + if (this.oscpos > 4096.0) { + this.oscpos -= 4096.0; + } + + // Modulators + if ((this.samplepos & 63) == 0) { + // Portamento + if (this.slidestep++ < 64) { + this.oscdelta -= this.slide; + } + + // Cutoff modulation + var tmp1 = this.envscaler * (this.filterenv - this.envoffset); + var tmp2 = this.accentgain * this.filterenv; + var effectivecutoff = Math.min(this.cutoff * Math.pow(2.0, tmp1 + tmp2), 20000); + + // Recalculate main filter coefficients + // TODO: optimize into lookup table! + var wc = ((2.0 * Math.PI) / samplerate) * effectivecutoff; + var r = this.resonance_skewed; + var fx = wc * 0.11253953951963826; // (1.0 / sqrt(2)) / (2.0 * PI) + this.tbf_b0 = (0.00045522346 + 6.1922189 * fx) / (1.0 + 12.358354 * fx + 4.4156345 * (fx * fx)); + var k = fx * (fx * (fx * (fx * (fx * (fx + 7198.6997) - 5837.7917) - 476.47308) + 614.95611) + 213.87126) + 16.998792; + this.tbf_g = (((k * 0.058823529411764705) - 1.0) * r + 1.0) * (1.0 + r); + this.tbf_k = k * r; + } + + // High pass filter 1 + var flt = this.onepole[0]; + flt[1] = flt[2] * sample + flt[3] * flt[0] + flt[4] * flt[1] + anti_denormal; // +plus denormalization constant + flt[0] = sample; + sample = flt[1]; + + // Main filter + feedback high pass + var tbf = this.tbfilter, tbfb0 = this.tbf_b0; // prefetch the array to save many object lookups + var fbhp = this.tbf_k * tbf[4]; + + flt = this.onepole[1]; + flt[1] = flt[2] * fbhp + flt[3] * flt[0] + flt[4] * flt[1] + anti_denormal; // +plus denormalization constant + flt[0] = fbhp; + fbhp = flt[1]; + + tbf[0] = sample - fbhp; + tbf[1] += 2 * tbfb0 * (tbf[0] - tbf[1] + tbf[2]); + tbf[2] += tbfb0 * (tbf[1] - 2 * tbf[2] + tbf[3]); + tbf[3] += tbfb0 * (tbf[2] - 2 * tbf[3] + tbf[4]); + tbf[4] += tbfb0 * (tbf[3] - 2 * tbf[4]); + sample = 2 * this.tbf_g * tbf[4]; + + // All pass filter + flt = this.onepole[2]; + flt[1] = flt[2] * sample + flt[3] * flt[0] + flt[4] * flt[1] + anti_denormal; // +plus denormalization constant + flt[0] = sample; + sample = flt[1]; + + // High pass filter 2 + flt = this.onepole[3]; + flt[1] = flt[2] * sample + flt[3] * flt[0] + flt[4] * flt[1] + anti_denormal; // +plus denormalization constant + flt[0] = sample; + sample = flt[1]; + + // Notch filter + flt = this.biquad[1]; + var biquady = flt[4] * sample + flt[5] * flt[0] + flt[6] * flt[1] + flt[7] * flt[2] + flt[8] * flt[3] + anti_denormal; // plus denormalization constant + flt[1] = flt[0]; + flt[0] = sample; + flt[3] = flt[2]; + flt[2] = biquady; + sample = biquady; + + // Calculate output gain with declicker filter + var outputgain = ((this.accentgain * 4.0 + 1.0) * this.ampenv); + flt = this.biquad[0]; + biquady = flt[4] * outputgain + flt[5] * flt[0] + flt[6] * flt[1] + flt[7] * flt[2] + flt[8] * flt[3] + anti_denormal; // plus denormalization constant + flt[1] = flt[0]; + flt[0] = outputgain; + flt[3] = flt[2]; + flt[2] = biquady; + outputgain = biquady; + + // Apply gain + sample *= outputgain; + + // Foldback distortion + if (sample > this.effective_dist_threshold || sample < -this.effective_dist_threshold) { + //sample = Math.abs(Math.abs((sample-effective_dist_threshold)%(effective_dist_threshold*4.0))-effective_dist_threshold*2.0)-effective_dist_threshold; + var clipped = (sample > 0.0 ? 1.0 : -1.0) * this.effective_dist_threshold; + sample = (Math.abs(Math.abs((((1.0 - this.dist_shape) * clipped + this.dist_shape * sample) - this.effective_dist_threshold) % (this.effective_dist_threshold * 4.0)) - this.effective_dist_threshold * 2.0) - this.effective_dist_threshold); + } + sample *= this.dist_gain; + + // Delay + var prev = this.delaybuffer[this.delaypos]; + this.delaybuffer[this.delaypos] = this.delay_send * sample + this.delay_feedback * prev + anti_denormal; + this.delaypos++; + if (this.delaypos >= this.delay_length) { + this.delaypos = 0; + } + sample += prev; + + return sample; + }; + + this.reset(); +} + +function loadwavetable(uri, callback) { + var img = new Image(); + + img.onload = function() { + var canvas = document.createElement('canvas'); + canvas.width = img.width; + canvas.height = img.height; + + var ctx = canvas.getContext('2d'); + ctx.drawImage(img, 0, 0); + + var data = ctx.getImageData(0, 0, canvas.width, canvas.height); + + wavetable = new Float32Array((new Uint8Array(data.data)).buffer); + + callback(); + }; + + img.src = uri; +} + +function genwavetable() { + // create a sine wave lookup table (because Math.sin is slow) + var i; + var stab = new Float32Array(4096); + for (i = 0; i < 4096; i++) { + stab[i] = Math.sin(2.0 * Math.PI * (i / 4096.0)); + } + + var last = 0; + var j, k, h, m, f, invh; + + // create the wavetable and zero it out (because not all browsers do that) + var wavetable = new Float32Array(2 * 524288); + for (i = 0; i < 2 * 524288; i++) { + wavetable[i] = 0.0; + } + + // create a waveform for each midi note + for (i = 0; i < 128; i++) { + // compute the number of partials in the waveform + h = Math.round((samplerate >> 1) / (440.0 * Math.pow(2.0, (i - 69.0) / 12.0))); + + // skip this note if the number of partials is equal to the previously generated waveform + if (h == last) { + continue; + } + + // compute the waveform using fourier series up to h partials + invh = 1.0 / h; + for (j = 1; j <= h; j++) { + m = ((m = Math.cos((j - 1) * (0.5 * Math.PI) / invh)) * m) / j; + + // render this partial to the wavetable + for (k = 0; k < 4096; k++) { + f = m * stab[(j * k) & 4095]; + wavetable[1 + (k + (i << 12))] += f; + + // only add odd partials to the square wave table + if (j & 1) { + wavetable[524288 + k + (i << 12)] += f; + } + } + } + + last = h; + } + + // normalize the wavetable + var max0 = 0; + var max1 = 0; + for (i = 0; i < 524288; i++) { + max0 = Math.max(max0, Math.abs(wavetable[i])); + max1 = Math.max(max1, Math.abs(wavetable[524288 + i])); + } + + max0 = 1.0 / max0; + max1 = 1.0 / max1; + for (i = 0; i < 524288; i++) { + wavetable[i] *= max0; + wavetable[524288 + i] *= max1; + } + + return wavetable +} diff --git a/assets/javascripts/vendor/ember.js b/assets/javascripts/vendor/ember.js new file mode 100644 index 0000000..7d5ea73 --- /dev/null +++ b/assets/javascripts/vendor/ember.js @@ -0,0 +1,48219 @@ +/*! + * @overview Ember - JavaScript Application Framework + * @copyright Copyright 2011-2014 Tilde Inc. and contributors + * Portions Copyright 2006-2011 Strobe Inc. + * Portions Copyright 2008-2011 Apple Inc. All rights reserved. + * @license Licensed under MIT license + * See https://raw.github.com/emberjs/ember.js/master/LICENSE + * @version 1.7.0 + */ + +(function() { +var define, requireModule, require, requirejs, Ember; + +(function() { + Ember = this.Ember = this.Ember || {}; + if (typeof Ember === 'undefined') { Ember = {} }; + + if (typeof Ember.__loader === 'undefined') { + var registry = {}, seen = {}; + + define = function(name, deps, callback) { + registry[name] = { deps: deps, callback: callback }; + }; + + requirejs = require = requireModule = function(name) { + if (seen.hasOwnProperty(name)) { return seen[name]; } + seen[name] = {}; + + if (!registry[name]) { + throw new Error("Could not find module " + name); + } + + var mod = registry[name], + deps = mod.deps, + callback = mod.callback, + reified = [], + exports; + + for (var i=0, l=deps.length; i 3 ? slice.call(arguments, 3) : undefined; + if (!this.currentInstance) { createAutorun(this); } + return this.currentInstance.schedule(queueName, target, method, args, false, stack); + }, + + deferOnce: function(queueName, target, method /* , args */) { + if (!method) { + method = target; + target = null; + } + + if (isString(method)) { + method = target[method]; + } + + var stack = this.DEBUG ? new Error() : undefined, + args = arguments.length > 3 ? slice.call(arguments, 3) : undefined; + if (!this.currentInstance) { createAutorun(this); } + return this.currentInstance.schedule(queueName, target, method, args, true, stack); + }, + + setTimeout: function() { + var args = slice.call(arguments), + length = args.length, + method, wait, target, + methodOrTarget, methodOrWait, methodOrArgs; + + if (length === 0) { + return; + } else if (length === 1) { + method = args.shift(); + wait = 0; + } else if (length === 2) { + methodOrTarget = args[0]; + methodOrWait = args[1]; + + if (isFunction(methodOrWait) || isFunction(methodOrTarget[methodOrWait])) { + target = args.shift(); + method = args.shift(); + wait = 0; + } else if (isCoercableNumber(methodOrWait)) { + method = args.shift(); + wait = args.shift(); + } else { + method = args.shift(); + wait = 0; + } + } else { + var last = args[args.length - 1]; + + if (isCoercableNumber(last)) { + wait = args.pop(); + } else { + wait = 0; + } + + methodOrTarget = args[0]; + methodOrArgs = args[1]; + + if (isFunction(methodOrArgs) || (isString(methodOrArgs) && + methodOrTarget !== null && + methodOrArgs in methodOrTarget)) { + target = args.shift(); + method = args.shift(); + } else { + method = args.shift(); + } + } + + var executeAt = (+new Date()) + parseInt(wait, 10); + + if (isString(method)) { + method = target[method]; + } + + var onError = getOnError(this.options); + + function fn() { + if (onError) { + try { + method.apply(target, args); + } catch (e) { + onError(e); + } + } else { + method.apply(target, args); + } + } + + // find position to insert + var i = searchTimer(executeAt, timers); + + timers.splice(i, 0, executeAt, fn); + + updateLaterTimer(this, executeAt, wait); + + return fn; + }, + + throttle: function(target, method /* , args, wait, [immediate] */) { + var self = this, + args = arguments, + immediate = pop.call(args), + wait, + throttler, + index, + timer; + + if (isNumber(immediate) || isString(immediate)) { + wait = immediate; + immediate = true; + } else { + wait = pop.call(args); + } + + wait = parseInt(wait, 10); + + index = findThrottler(target, method, this._throttlers); + if (index > -1) { return this._throttlers[index]; } // throttled + + timer = global.setTimeout(function() { + if (!immediate) { + self.run.apply(self, args); + } + var index = findThrottler(target, method, self._throttlers); + if (index > -1) { + self._throttlers.splice(index, 1); + } + }, wait); + + if (immediate) { + self.run.apply(self, args); + } + + throttler = [target, method, timer]; + + this._throttlers.push(throttler); + + return throttler; + }, + + debounce: function(target, method /* , args, wait, [immediate] */) { + var self = this, + args = arguments, + immediate = pop.call(args), + wait, + index, + debouncee, + timer; + + if (isNumber(immediate) || isString(immediate)) { + wait = immediate; + immediate = false; + } else { + wait = pop.call(args); + } + + wait = parseInt(wait, 10); + // Remove debouncee + index = findDebouncee(target, method, this._debouncees); + + if (index > -1) { + debouncee = this._debouncees[index]; + this._debouncees.splice(index, 1); + clearTimeout(debouncee[2]); + } + + timer = global.setTimeout(function() { + if (!immediate) { + self.run.apply(self, args); + } + var index = findDebouncee(target, method, self._debouncees); + if (index > -1) { + self._debouncees.splice(index, 1); + } + }, wait); + + if (immediate && index === -1) { + self.run.apply(self, args); + } + + debouncee = [target, method, timer]; + + self._debouncees.push(debouncee); + + return debouncee; + }, + + cancelTimers: function() { + var clearItems = function(item) { + clearTimeout(item[2]); + }; + + each(this._throttlers, clearItems); + this._throttlers = []; + + each(this._debouncees, clearItems); + this._debouncees = []; + + if (this._laterTimer) { + clearTimeout(this._laterTimer); + this._laterTimer = null; + } + timers = []; + + if (this._autorun) { + clearTimeout(this._autorun); + this._autorun = null; + } + }, + + hasTimers: function() { + return !!timers.length || !!this._debouncees.length || !!this._throttlers.length || this._autorun; + }, + + cancel: function(timer) { + var timerType = typeof timer; + + if (timer && timerType === 'object' && timer.queue && timer.method) { // we're cancelling a deferOnce + return timer.queue.cancel(timer); + } else if (timerType === 'function') { // we're cancelling a setTimeout + for (var i = 0, l = timers.length; i < l; i += 2) { + if (timers[i + 1] === timer) { + timers.splice(i, 2); // remove the two elements + return true; + } + } + } else if (Object.prototype.toString.call(timer) === "[object Array]"){ // we're cancelling a throttle or debounce + return this._cancelItem(findThrottler, this._throttlers, timer) || + this._cancelItem(findDebouncee, this._debouncees, timer); + } else { + return; // timer was null or not a timer + } + }, + + _cancelItem: function(findMethod, array, timer){ + var item, + index; + + if (timer.length < 3) { return false; } + + index = findMethod(timer[0], timer[1], array); + + if(index > -1) { + + item = array[index]; + + if(item[2] === timer[2]){ + array.splice(index, 1); + clearTimeout(timer[2]); + return true; + } + } + + return false; + } + }; + + Backburner.prototype.schedule = Backburner.prototype.defer; + Backburner.prototype.scheduleOnce = Backburner.prototype.deferOnce; + Backburner.prototype.later = Backburner.prototype.setTimeout; + + if (needsIETryCatchFix) { + var originalRun = Backburner.prototype.run; + Backburner.prototype.run = wrapInTryCatch(originalRun); + + var originalEnd = Backburner.prototype.end; + Backburner.prototype.end = wrapInTryCatch(originalEnd); + } + + function wrapInTryCatch(func) { + return function () { + try { + return func.apply(this, arguments); + } catch (e) { + throw e; + } + }; + } + + function getOnError(options) { + return options.onError || (options.onErrorTarget && options.onErrorTarget[options.onErrorMethod]); + } + + + function createAutorun(backburner) { + backburner.begin(); + backburner._autorun = global.setTimeout(function() { + backburner._autorun = null; + backburner.end(); + }); + } + + function updateLaterTimer(self, executeAt, wait) { + if (!self._laterTimer || executeAt < self._laterTimerExpiresAt) { + self._laterTimer = global.setTimeout(function() { + self._laterTimer = null; + self._laterTimerExpiresAt = null; + executeTimers(self); + }, wait); + self._laterTimerExpiresAt = executeAt; + } + } + + function executeTimers(self) { + var now = +new Date(), + time, fns, i, l; + + self.run(function() { + i = searchTimer(now, timers); + + fns = timers.splice(0, i); + + for (i = 1, l = fns.length; i < l; i += 2) { + self.schedule(self.options.defaultQueue, null, fns[i]); + } + }); + + if (timers.length) { + updateLaterTimer(self, timers[0], timers[0] - now); + } + } + + function findDebouncee(target, method, debouncees) { + return findItem(target, method, debouncees); + } + + function findThrottler(target, method, throttlers) { + return findItem(target, method, throttlers); + } + + function findItem(target, method, collection) { + var item, + index = -1; + + for (var i = 0, l = collection.length; i < l; i++) { + item = collection[i]; + if (item[0] === target && item[1] === method) { + index = i; + break; + } + } + + return index; + } + + function searchTimer(time, timers) { + var start = 0, + end = timers.length - 2, + middle, l; + + while (start < end) { + // since timers is an array of pairs 'l' will always + // be an integer + l = (end - start) / 2; + + // compensate for the index in case even number + // of pairs inside timers + middle = start + l - (l % 2); + + if (time >= timers[middle]) { + start = middle + 2; + } else { + end = middle; + } + } + + return (time >= timers[start]) ? start + 2 : start; + } + + __exports__.Backburner = Backburner; + }); +define("backburner/deferred_action_queues", + ["backburner/utils","backburner/queue","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Utils = __dependency1__["default"]; + var Queue = __dependency2__.Queue; + + var each = Utils.each, + isString = Utils.isString; + + function DeferredActionQueues(queueNames, options) { + var queues = this.queues = {}; + this.queueNames = queueNames = queueNames || []; + + this.options = options; + + each(queueNames, function(queueName) { + queues[queueName] = new Queue(this, queueName, options); + }); + } + + DeferredActionQueues.prototype = { + queueNames: null, + queues: null, + options: null, + + schedule: function(queueName, target, method, args, onceFlag, stack) { + var queues = this.queues, + queue = queues[queueName]; + + if (!queue) { throw new Error("You attempted to schedule an action in a queue (" + queueName + ") that doesn't exist"); } + + if (onceFlag) { + return queue.pushUnique(target, method, args, stack); + } else { + return queue.push(target, method, args, stack); + } + }, + + invoke: function(target, method, args, _) { + if (args && args.length > 0) { + method.apply(target, args); + } else { + method.call(target); + } + }, + + invokeWithOnError: function(target, method, args, onError) { + try { + if (args && args.length > 0) { + method.apply(target, args); + } else { + method.call(target); + } + } catch(error) { + onError(error); + } + }, + + flush: function() { + var queues = this.queues, + queueNames = this.queueNames, + queueName, queue, queueItems, priorQueueNameIndex, + queueNameIndex = 0, numberOfQueues = queueNames.length, + options = this.options, + onError = options.onError || (options.onErrorTarget && options.onErrorTarget[options.onErrorMethod]), + invoke = onError ? this.invokeWithOnError : this.invoke; + + outerloop: + while (queueNameIndex < numberOfQueues) { + queueName = queueNames[queueNameIndex]; + queue = queues[queueName]; + queueItems = queue._queueBeingFlushed = queue._queue.slice(); + queue._queue = []; + + var queueOptions = queue.options, // TODO: write a test for this + before = queueOptions && queueOptions.before, + after = queueOptions && queueOptions.after, + target, method, args, stack, + queueIndex = 0, numberOfQueueItems = queueItems.length; + + if (numberOfQueueItems && before) { before(); } + + while (queueIndex < numberOfQueueItems) { + target = queueItems[queueIndex]; + method = queueItems[queueIndex+1]; + args = queueItems[queueIndex+2]; + stack = queueItems[queueIndex+3]; // Debugging assistance + + if (isString(method)) { method = target[method]; } + + // method could have been nullified / canceled during flush + if (method) { + invoke(target, method, args, onError); + } + + queueIndex += 4; + } + + queue._queueBeingFlushed = null; + if (numberOfQueueItems && after) { after(); } + + if ((priorQueueNameIndex = indexOfPriorQueueWithActions(this, queueNameIndex)) !== -1) { + queueNameIndex = priorQueueNameIndex; + continue outerloop; + } + + queueNameIndex++; + } + } + }; + + function indexOfPriorQueueWithActions(daq, currentQueueIndex) { + var queueName, queue; + + for (var i = 0, l = currentQueueIndex; i <= l; i++) { + queueName = daq.queueNames[i]; + queue = daq.queues[queueName]; + if (queue._queue.length) { return i; } + } + + return -1; + } + + __exports__.DeferredActionQueues = DeferredActionQueues; + }); +define("backburner/queue", + ["exports"], + function(__exports__) { + "use strict"; + function Queue(daq, name, options) { + this.daq = daq; + this.name = name; + this.globalOptions = options; + this.options = options[name]; + this._queue = []; + } + + Queue.prototype = { + daq: null, + name: null, + options: null, + onError: null, + _queue: null, + + push: function(target, method, args, stack) { + var queue = this._queue; + queue.push(target, method, args, stack); + return {queue: this, target: target, method: method}; + }, + + pushUnique: function(target, method, args, stack) { + var queue = this._queue, currentTarget, currentMethod, i, l; + + for (i = 0, l = queue.length; i < l; i += 4) { + currentTarget = queue[i]; + currentMethod = queue[i+1]; + + if (currentTarget === target && currentMethod === method) { + queue[i+2] = args; // replace args + queue[i+3] = stack; // replace stack + return {queue: this, target: target, method: method}; + } + } + + queue.push(target, method, args, stack); + return {queue: this, target: target, method: method}; + }, + + // TODO: remove me, only being used for Ember.run.sync + flush: function() { + var queue = this._queue, + globalOptions = this.globalOptions, + options = this.options, + before = options && options.before, + after = options && options.after, + onError = globalOptions.onError || (globalOptions.onErrorTarget && globalOptions.onErrorTarget[globalOptions.onErrorMethod]), + target, method, args, stack, i, l = queue.length; + + if (l && before) { before(); } + for (i = 0; i < l; i += 4) { + target = queue[i]; + method = queue[i+1]; + args = queue[i+2]; + stack = queue[i+3]; // Debugging assistance + + // TODO: error handling + if (args && args.length > 0) { + if (onError) { + try { + method.apply(target, args); + } catch (e) { + onError(e); + } + } else { + method.apply(target, args); + } + } else { + if (onError) { + try { + method.call(target); + } catch(e) { + onError(e); + } + } else { + method.call(target); + } + } + } + if (l && after) { after(); } + + // check if new items have been added + if (queue.length > l) { + this._queue = queue.slice(l); + this.flush(); + } else { + this._queue.length = 0; + } + }, + + cancel: function(actionToCancel) { + var queue = this._queue, currentTarget, currentMethod, i, l; + + for (i = 0, l = queue.length; i < l; i += 4) { + currentTarget = queue[i]; + currentMethod = queue[i+1]; + + if (currentTarget === actionToCancel.target && currentMethod === actionToCancel.method) { + queue.splice(i, 4); + return true; + } + } + + // if not found in current queue + // could be in the queue that is being flushed + queue = this._queueBeingFlushed; + if (!queue) { + return; + } + for (i = 0, l = queue.length; i < l; i += 4) { + currentTarget = queue[i]; + currentMethod = queue[i+1]; + + if (currentTarget === actionToCancel.target && currentMethod === actionToCancel.method) { + // don't mess with array during flush + // just nullify the method + queue[i+1] = null; + return true; + } + } + } + }; + + __exports__.Queue = Queue; + }); +define("backburner/utils", + ["exports"], + function(__exports__) { + "use strict"; + __exports__["default"] = { + each: function(collection, callback) { + for (var i = 0; i < collection.length; i++) { + callback(collection[i]); + } + }, + + isString: function(suspect) { + return typeof suspect === 'string'; + }, + + isFunction: function(suspect) { + return typeof suspect === 'function'; + }, + + isNumber: function(suspect) { + return typeof suspect === 'number'; + } + }; + }); + +define("calculateVersion", + [], + function() { + "use strict"; + 'use strict'; + + var fs = require('fs'); + var path = require('path'); + + module.exports = function () { + var packageVersion = require('../package.json').version; + var output = [packageVersion]; + var gitPath = path.join(__dirname,'..','.git'); + var headFilePath = path.join(gitPath, 'HEAD'); + + if (packageVersion.indexOf('+') > -1) { + try { + if (fs.existsSync(headFilePath)) { + var headFile = fs.readFileSync(headFilePath, {encoding: 'utf8'}); + var branchName = headFile.split('/').slice(-1)[0].trim(); + var refPath = headFile.split(' ')[1]; + var branchSHA; + + if (refPath) { + var branchPath = path.join(gitPath, refPath.trim()); + branchSHA = fs.readFileSync(branchPath); + } else { + branchSHA = branchName; + } + + output.push(branchSHA.slice(0,10)); + } + } catch (err) { + console.error(err.stack); + } + return output.join('.'); + } else { + return packageVersion; + } + }; + }); +define("container", + ["container/container","exports"], + function(__dependency1__, __exports__) { + "use strict"; + /* + Public api for the container is still in flux. + The public api, specified on the application namespace should be considered the stable api. + // @module container + @private + */ + + /* + Flag to enable/disable model factory injections (disabled by default) + If model factory injections are enabled, models should not be + accessed globally (only through `container.lookupFactory('model:modelName'))`); + */ + Ember.MODEL_FACTORY_INJECTIONS = false; + + if (Ember.ENV && typeof Ember.ENV.MODEL_FACTORY_INJECTIONS !== 'undefined') { + Ember.MODEL_FACTORY_INJECTIONS = !!Ember.ENV.MODEL_FACTORY_INJECTIONS; + } + + + var Container = __dependency1__["default"]; + + __exports__["default"] = Container; + }); +define("container/container", + ["container/inheriting_dict","ember-metal/core","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var InheritingDict = __dependency1__["default"]; + var Ember = __dependency2__["default"]; + // Ember.assert + + // A lightweight container that helps to assemble and decouple components. + // Public api for the container is still in flux. + // The public api, specified on the application namespace should be considered the stable api. + function Container(parent) { + this.parent = parent; + this.children = []; + + this.resolver = parent && parent.resolver || function() {}; + + this.registry = new InheritingDict(parent && parent.registry); + this.cache = new InheritingDict(parent && parent.cache); + this.factoryCache = new InheritingDict(parent && parent.factoryCache); + this.resolveCache = new InheritingDict(parent && parent.resolveCache); + this.typeInjections = new InheritingDict(parent && parent.typeInjections); + this.injections = {}; + + this.factoryTypeInjections = new InheritingDict(parent && parent.factoryTypeInjections); + this.factoryInjections = {}; + + this._options = new InheritingDict(parent && parent._options); + this._typeOptions = new InheritingDict(parent && parent._typeOptions); + } + + Container.prototype = { + + /** + @property parent + @type Container + @default null + */ + parent: null, + + /** + @property children + @type Array + @default [] + */ + children: null, + + /** + @property resolver + @type function + */ + resolver: null, + + /** + @property registry + @type InheritingDict + */ + registry: null, + + /** + @property cache + @type InheritingDict + */ + cache: null, + + /** + @property typeInjections + @type InheritingDict + */ + typeInjections: null, + + /** + @property injections + @type Object + @default {} + */ + injections: null, + + /** + @private + + @property _options + @type InheritingDict + @default null + */ + _options: null, + + /** + @private + + @property _typeOptions + @type InheritingDict + */ + _typeOptions: null, + + /** + Returns a new child of the current container. These children are configured + to correctly inherit from the current container. + + @method child + @return {Container} + */ + child: function() { + var container = new Container(this); + this.children.push(container); + return container; + }, + + /** + Sets a key-value pair on the current container. If a parent container, + has the same key, once set on a child, the parent and child will diverge + as expected. + + @method set + @param {Object} object + @param {String} key + @param {any} value + */ + set: function(object, key, value) { + object[key] = value; + }, + + /** + Registers a factory for later injection. + + Example: + + ```javascript + var container = new Container(); + + container.register('model:user', Person, {singleton: false }); + container.register('fruit:favorite', Orange); + container.register('communication:main', Email, {singleton: false}); + ``` + + @method register + @param {String} fullName + @param {Function} factory + @param {Object} options + */ + register: function(fullName, factory, options) { + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + + if (factory === undefined) { + throw new TypeError('Attempting to register an unknown factory: `' + fullName + '`'); + } + + var normalizedName = this.normalize(fullName); + + if (this.cache.has(normalizedName)) { + throw new Error('Cannot re-register: `' + fullName +'`, as it has already been looked up.'); + } + + this.registry.set(normalizedName, factory); + this._options.set(normalizedName, options || {}); + }, + + /** + Unregister a fullName + + ```javascript + var container = new Container(); + container.register('model:user', User); + + container.lookup('model:user') instanceof User //=> true + + container.unregister('model:user') + container.lookup('model:user') === undefined //=> true + ``` + + @method unregister + @param {String} fullName + */ + unregister: function(fullName) { + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + + var normalizedName = this.normalize(fullName); + + this.registry.remove(normalizedName); + this.cache.remove(normalizedName); + this.factoryCache.remove(normalizedName); + this.resolveCache.remove(normalizedName); + this._options.remove(normalizedName); + }, + + /** + Given a fullName return the corresponding factory. + + By default `resolve` will retrieve the factory from + its container's registry. + + ```javascript + var container = new Container(); + container.register('api:twitter', Twitter); + + container.resolve('api:twitter') // => Twitter + ``` + + Optionally the container can be provided with a custom resolver. + If provided, `resolve` will first provide the custom resolver + the opportunity to resolve the fullName, otherwise it will fallback + to the registry. + + ```javascript + var container = new Container(); + container.resolver = function(fullName) { + // lookup via the module system of choice + }; + + // the twitter factory is added to the module system + container.resolve('api:twitter') // => Twitter + ``` + + @method resolve + @param {String} fullName + @return {Function} fullName's factory + */ + resolve: function(fullName) { + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + return resolve(this, this.normalize(fullName)); + }, + + /** + A hook that can be used to describe how the resolver will + attempt to find the factory. + + For example, the default Ember `.describe` returns the full + class name (including namespace) where Ember's resolver expects + to find the `fullName`. + + @method describe + @param {String} fullName + @return {string} described fullName + */ + describe: function(fullName) { + return fullName; + }, + + /** + A hook to enable custom fullName normalization behaviour + + @method normalize + @param {String} fullName + @return {string} normalized fullName + */ + normalize: function(fullName) { + return fullName; + }, + + /** + @method makeToString + + @param {any} factory + @param {string} fullName + @return {function} toString function + */ + makeToString: function(factory, fullName) { + return factory.toString(); + }, + + /** + Given a fullName return a corresponding instance. + + The default behaviour is for lookup to return a singleton instance. + The singleton is scoped to the container, allowing multiple containers + to all have their own locally scoped singletons. + + ```javascript + var container = new Container(); + container.register('api:twitter', Twitter); + + var twitter = container.lookup('api:twitter'); + + twitter instanceof Twitter; // => true + + // by default the container will return singletons + var twitter2 = container.lookup('api:twitter'); + twitter2 instanceof Twitter; // => true + + twitter === twitter2; //=> true + ``` + + If singletons are not wanted an optional flag can be provided at lookup. + + ```javascript + var container = new Container(); + container.register('api:twitter', Twitter); + + var twitter = container.lookup('api:twitter', { singleton: false }); + var twitter2 = container.lookup('api:twitter', { singleton: false }); + + twitter === twitter2; //=> false + ``` + + @method lookup + @param {String} fullName + @param {Object} options + @return {any} + */ + lookup: function(fullName, options) { + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + return lookup(this, this.normalize(fullName), options); + }, + + /** + Given a fullName return the corresponding factory. + + @method lookupFactory + @param {String} fullName + @return {any} + */ + lookupFactory: function(fullName) { + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + return factoryFor(this, this.normalize(fullName)); + }, + + /** + Given a fullName check if the container is aware of its factory + or singleton instance. + + @method has + @param {String} fullName + @return {Boolean} + */ + has: function(fullName) { + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + return has(this, this.normalize(fullName)); + }, + + /** + Allow registering options for all factories of a type. + + ```javascript + var container = new Container(); + + // if all of type `connection` must not be singletons + container.optionsForType('connection', { singleton: false }); + + container.register('connection:twitter', TwitterConnection); + container.register('connection:facebook', FacebookConnection); + + var twitter = container.lookup('connection:twitter'); + var twitter2 = container.lookup('connection:twitter'); + + twitter === twitter2; // => false + + var facebook = container.lookup('connection:facebook'); + var facebook2 = container.lookup('connection:facebook'); + + facebook === facebook2; // => false + ``` + + @method optionsForType + @param {String} type + @param {Object} options + */ + optionsForType: function(type, options) { + if (this.parent) { illegalChildOperation('optionsForType'); } + + this._typeOptions.set(type, options); + }, + + /** + @method options + @param {String} type + @param {Object} options + */ + options: function(type, options) { + this.optionsForType(type, options); + }, + + /** + Used only via `injection`. + + Provides a specialized form of injection, specifically enabling + all objects of one type to be injected with a reference to another + object. + + For example, provided each object of type `controller` needed a `router`. + one would do the following: + + ```javascript + var container = new Container(); + + container.register('router:main', Router); + container.register('controller:user', UserController); + container.register('controller:post', PostController); + + container.typeInjection('controller', 'router', 'router:main'); + + var user = container.lookup('controller:user'); + var post = container.lookup('controller:post'); + + user.router instanceof Router; //=> true + post.router instanceof Router; //=> true + + // both controllers share the same router + user.router === post.router; //=> true + ``` + + @private + @method typeInjection + @param {String} type + @param {String} property + @param {String} fullName + */ + typeInjection: function(type, property, fullName) { + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + if (this.parent) { illegalChildOperation('typeInjection'); } + + var fullNameType = fullName.split(':')[0]; + if(fullNameType === type) { + throw new Error('Cannot inject a `' + fullName + '` on other ' + type + '(s). Register the `' + fullName + '` as a different type and perform the typeInjection.'); + } + addTypeInjection(this.typeInjections, type, property, fullName); + }, + + /** + Defines injection rules. + + These rules are used to inject dependencies onto objects when they + are instantiated. + + Two forms of injections are possible: + + * Injecting one fullName on another fullName + * Injecting one fullName on a type + + Example: + + ```javascript + var container = new Container(); + + container.register('source:main', Source); + container.register('model:user', User); + container.register('model:post', Post); + + // injecting one fullName on another fullName + // eg. each user model gets a post model + container.injection('model:user', 'post', 'model:post'); + + // injecting one fullName on another type + container.injection('model', 'source', 'source:main'); + + var user = container.lookup('model:user'); + var post = container.lookup('model:post'); + + user.source instanceof Source; //=> true + post.source instanceof Source; //=> true + + user.post instanceof Post; //=> true + + // and both models share the same source + user.source === post.source; //=> true + ``` + + @method injection + @param {String} factoryName + @param {String} property + @param {String} injectionName + */ + injection: function(fullName, property, injectionName) { + if (this.parent) { illegalChildOperation('injection'); } + + validateFullName(injectionName); + var normalizedInjectionName = this.normalize(injectionName); + + if (fullName.indexOf(':') === -1) { + return this.typeInjection(fullName, property, normalizedInjectionName); + } + + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + var normalizedName = this.normalize(fullName); + + if (this.cache.has(normalizedName)) { + throw new Error("Attempted to register an injection for a type that has already been looked up. ('" + normalizedName + "', '" + property + "', '" + injectionName + "')"); + } + addInjection(this.injections, normalizedName, property, normalizedInjectionName); + }, + + + /** + Used only via `factoryInjection`. + + Provides a specialized form of injection, specifically enabling + all factory of one type to be injected with a reference to another + object. + + For example, provided each factory of type `model` needed a `store`. + one would do the following: + + ```javascript + var container = new Container(); + + container.register('store:main', SomeStore); + + container.factoryTypeInjection('model', 'store', 'store:main'); + + var store = container.lookup('store:main'); + var UserFactory = container.lookupFactory('model:user'); + + UserFactory.store instanceof SomeStore; //=> true + ``` + + @private + @method factoryTypeInjection + @param {String} type + @param {String} property + @param {String} fullName + */ + factoryTypeInjection: function(type, property, fullName) { + if (this.parent) { illegalChildOperation('factoryTypeInjection'); } + + addTypeInjection(this.factoryTypeInjections, type, property, this.normalize(fullName)); + }, + + /** + Defines factory injection rules. + + Similar to regular injection rules, but are run against factories, via + `Container#lookupFactory`. + + These rules are used to inject objects onto factories when they + are looked up. + + Two forms of injections are possible: + + * Injecting one fullName on another fullName + * Injecting one fullName on a type + + Example: + + ```javascript + var container = new Container(); + + container.register('store:main', Store); + container.register('store:secondary', OtherStore); + container.register('model:user', User); + container.register('model:post', Post); + + // injecting one fullName on another type + container.factoryInjection('model', 'store', 'store:main'); + + // injecting one fullName on another fullName + container.factoryInjection('model:post', 'secondaryStore', 'store:secondary'); + + var UserFactory = container.lookupFactory('model:user'); + var PostFactory = container.lookupFactory('model:post'); + var store = container.lookup('store:main'); + + UserFactory.store instanceof Store; //=> true + UserFactory.secondaryStore instanceof OtherStore; //=> false + + PostFactory.store instanceof Store; //=> true + PostFactory.secondaryStore instanceof OtherStore; //=> true + + // and both models share the same source instance + UserFactory.store === PostFactory.store; //=> true + ``` + + @method factoryInjection + @param {String} factoryName + @param {String} property + @param {String} injectionName + */ + factoryInjection: function(fullName, property, injectionName) { + if (this.parent) { illegalChildOperation('injection'); } + + var normalizedName = this.normalize(fullName); + var normalizedInjectionName = this.normalize(injectionName); + + validateFullName(injectionName); + + if (fullName.indexOf(':') === -1) { + return this.factoryTypeInjection(normalizedName, property, normalizedInjectionName); + } + + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + + if (this.factoryCache.has(normalizedName)) { + throw new Error('Attempted to register a factoryInjection for a type that has already ' + + 'been looked up. (\'' + normalizedName + '\', \'' + property + '\', \'' + injectionName + '\')'); + } + + addInjection(this.factoryInjections, normalizedName, property, normalizedInjectionName); + }, + + /** + A depth first traversal, destroying the container, its descendant containers and all + their managed objects. + + @method destroy + */ + destroy: function() { + for (var i = 0, length = this.children.length; i < length; i++) { + this.children[i].destroy(); + } + + this.children = []; + + eachDestroyable(this, function(item) { + item.destroy(); + }); + + this.parent = undefined; + this.isDestroyed = true; + }, + + /** + @method reset + */ + reset: function() { + for (var i = 0, length = this.children.length; i < length; i++) { + resetCache(this.children[i]); + } + + resetCache(this); + } + }; + + function resolve(container, normalizedName) { + var cached = container.resolveCache.get(normalizedName); + if (cached) { return cached; } + + var resolved = container.resolver(normalizedName) || container.registry.get(normalizedName); + container.resolveCache.set(normalizedName, resolved); + + return resolved; + } + + function has(container, fullName){ + if (container.cache.has(fullName)) { + return true; + } + + return !!container.resolve(fullName); + } + + function lookup(container, fullName, options) { + options = options || {}; + + if (container.cache.has(fullName) && options.singleton !== false) { + return container.cache.get(fullName); + } + + var value = instantiate(container, fullName); + + if (value === undefined) { return; } + + if (isSingleton(container, fullName) && options.singleton !== false) { + container.cache.set(fullName, value); + } + + return value; + } + + function illegalChildOperation(operation) { + throw new Error(operation + ' is not currently supported on child containers'); + } + + function isSingleton(container, fullName) { + var singleton = option(container, fullName, 'singleton'); + + return singleton !== false; + } + + function buildInjections(container, injections) { + var hash = {}; + + if (!injections) { return hash; } + + var injection, injectable; + + for (var i = 0, length = injections.length; i < length; i++) { + injection = injections[i]; + injectable = lookup(container, injection.fullName); + + if (injectable !== undefined) { + hash[injection.property] = injectable; + } else { + throw new Error('Attempting to inject an unknown injection: `' + injection.fullName + '`'); + } + } + + return hash; + } + + function option(container, fullName, optionName) { + var options = container._options.get(fullName); + + if (options && options[optionName] !== undefined) { + return options[optionName]; + } + + var type = fullName.split(':')[0]; + options = container._typeOptions.get(type); + + if (options) { + return options[optionName]; + } + } + + function factoryFor(container, fullName) { + var cache = container.factoryCache; + if (cache.has(fullName)) { + return cache.get(fullName); + } + var factory = container.resolve(fullName); + if (factory === undefined) { return; } + + var type = fullName.split(':')[0]; + if (!factory || typeof factory.extend !== 'function' || (!Ember.MODEL_FACTORY_INJECTIONS && type === 'model')) { + // TODO: think about a 'safe' merge style extension + // for now just fallback to create time injection + return factory; + } else { + var injections = injectionsFor(container, fullName); + var factoryInjections = factoryInjectionsFor(container, fullName); + + factoryInjections._toString = container.makeToString(factory, fullName); + + var injectedFactory = factory.extend(injections); + injectedFactory.reopenClass(factoryInjections); + + cache.set(fullName, injectedFactory); + + return injectedFactory; + } + } + + function injectionsFor(container, fullName) { + var splitName = fullName.split(':'), + type = splitName[0], + injections = []; + + injections = injections.concat(container.typeInjections.get(type) || []); + injections = injections.concat(container.injections[fullName] || []); + + injections = buildInjections(container, injections); + injections._debugContainerKey = fullName; + injections.container = container; + + return injections; + } + + function factoryInjectionsFor(container, fullName) { + var splitName = fullName.split(':'), + type = splitName[0], + factoryInjections = []; + + factoryInjections = factoryInjections.concat(container.factoryTypeInjections.get(type) || []); + factoryInjections = factoryInjections.concat(container.factoryInjections[fullName] || []); + + factoryInjections = buildInjections(container, factoryInjections); + factoryInjections._debugContainerKey = fullName; + + return factoryInjections; + } + + function instantiate(container, fullName) { + var factory = factoryFor(container, fullName); + + if (option(container, fullName, 'instantiate') === false) { + return factory; + } + + if (factory) { + if (typeof factory.create !== 'function') { + throw new Error('Failed to create an instance of \'' + fullName + '\'. ' + + 'Most likely an improperly defined class or an invalid module export.'); + } + + if (typeof factory.extend === 'function') { + // assume the factory was extendable and is already injected + return factory.create(); + } else { + // assume the factory was extendable + // to create time injections + // TODO: support new'ing for instantiation and merge injections for pure JS Functions + return factory.create(injectionsFor(container, fullName)); + } + } + } + + function eachDestroyable(container, callback) { + container.cache.eachLocal(function(key, value) { + if (option(container, key, 'instantiate') === false) { return; } + callback(value); + }); + } + + function resetCache(container) { + container.cache.eachLocal(function(key, value) { + if (option(container, key, 'instantiate') === false) { return; } + value.destroy(); + }); + container.cache.dict = {}; + } + + function addTypeInjection(rules, type, property, fullName) { + var injections = rules.get(type); + + if (!injections) { + injections = []; + rules.set(type, injections); + } + + injections.push({ + property: property, + fullName: fullName + }); + } + + var VALID_FULL_NAME_REGEXP = /^[^:]+.+:[^:]+$/; + function validateFullName(fullName) { + if (!VALID_FULL_NAME_REGEXP.test(fullName)) { + throw new TypeError('Invalid Fullname, expected: `type:name` got: ' + fullName); + } + return true; + } + + function addInjection(rules, factoryName, property, injectionName) { + var injections = rules[factoryName] = rules[factoryName] || []; + injections.push({ property: property, fullName: injectionName }); + } + + __exports__["default"] = Container; + }); +define("container/inheriting_dict", + ["exports"], + function(__exports__) { + "use strict"; + // A safe and simple inheriting object. + function InheritingDict(parent) { + this.parent = parent; + this.dict = {}; + } + + InheritingDict.prototype = { + + /** + @property parent + @type InheritingDict + @default null + */ + + parent: null, + + /** + Object used to store the current nodes data. + + @property dict + @type Object + @default Object + */ + dict: null, + + /** + Retrieve the value given a key, if the value is present at the current + level use it, otherwise walk up the parent hierarchy and try again. If + no matching key is found, return undefined. + + @method get + @param {String} key + @return {any} + */ + get: function(key) { + var dict = this.dict; + + if (dict.hasOwnProperty(key)) { + return dict[key]; + } + + if (this.parent) { + return this.parent.get(key); + } + }, + + /** + Set the given value for the given key, at the current level. + + @method set + @param {String} key + @param {Any} value + */ + set: function(key, value) { + this.dict[key] = value; + }, + + /** + Delete the given key + + @method remove + @param {String} key + */ + remove: function(key) { + delete this.dict[key]; + }, + + /** + Check for the existence of given a key, if the key is present at the current + level return true, otherwise walk up the parent hierarchy and try again. If + no matching key is found, return false. + + @method has + @param {String} key + @return {Boolean} + */ + has: function(key) { + var dict = this.dict; + + if (dict.hasOwnProperty(key)) { + return true; + } + + if (this.parent) { + return this.parent.has(key); + } + + return false; + }, + + /** + Iterate and invoke a callback for each local key-value pair. + + @method eachLocal + @param {Function} callback + @param {Object} binding + */ + eachLocal: function(callback, binding) { + var dict = this.dict; + + for (var prop in dict) { + if (dict.hasOwnProperty(prop)) { + callback.call(binding, prop, dict[prop]); + } + } + } + }; + + __exports__["default"] = InheritingDict; + }); +define("ember-application", + ["ember-metal/core","ember-runtime/system/lazy_load","ember-application/system/dag","ember-application/system/resolver","ember-application/system/application","ember-application/ext/controller"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__) { + "use strict"; + var Ember = __dependency1__["default"]; + var runLoadHooks = __dependency2__.runLoadHooks; + + /** + Ember Application + + @module ember + @submodule ember-application + @requires ember-views, ember-routing + */ + + var DAG = __dependency3__["default"]; + var Resolver = __dependency4__.Resolver; + var DefaultResolver = __dependency4__["default"]; + var Application = __dependency5__["default"]; + // side effect of extending ControllerMixin + + Ember.Application = Application; + Ember.DAG = DAG; + Ember.Resolver = Resolver; + Ember.DefaultResolver = DefaultResolver; + + runLoadHooks('Ember.Application', Application); + }); +define("ember-application/ext/controller", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/error","ember-metal/utils","ember-metal/computed","ember-runtime/mixins/controller","ember-routing/system/controller_for","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-application + */ + + var Ember = __dependency1__["default"]; + // Ember.assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var EmberError = __dependency4__["default"]; + var inspect = __dependency5__.inspect; + var computed = __dependency6__.computed; + var ControllerMixin = __dependency7__["default"]; + var meta = __dependency5__.meta; + var controllerFor = __dependency8__["default"]; + + function verifyNeedsDependencies(controller, container, needs) { + var dependency, i, l, missing = []; + + for (i=0, l=needs.length; i 1 ? 'they' : 'it') + " could not be found"); + } + } + + var defaultControllersComputedProperty = computed(function() { + var controller = this; + + return { + needs: get(controller, 'needs'), + container: get(controller, 'container'), + unknownProperty: function(controllerName) { + var needs = this.needs, + dependency, i, l; + for (i=0, l=needs.length; i 0) { + Ember.assert(' `' + inspect(this) + ' specifies `needs`, but does ' + + "not have a container. Please ensure this controller was " + + "instantiated with a container.", + this.container || meta(this, false).descs.controllers !== defaultControllersComputedProperty); + + if (this.container) { + verifyNeedsDependencies(this, this.container, needs); + } + + // if needs then initialize controllers proxy + get(this, 'controllers'); + } + + this._super.apply(this, arguments); + }, + + /** + @method controllerFor + @see {Ember.Route#controllerFor} + @deprecated Use `needs` instead + */ + controllerFor: function(controllerName) { + Ember.deprecate("Controller#controllerFor is deprecated, please use Controller#needs instead"); + return controllerFor(get(this, 'container'), controllerName); + }, + + /** + Stores the instances of other controllers available from within + this controller. Any controller listed by name in the `needs` + property will be accessible by name through this property. + + ```javascript + App.CommentsController = Ember.ArrayController.extend({ + needs: ['post'], + postTitle: function(){ + var currentPost = this.get('controllers.post'); // instance of App.PostController + return currentPost.get('title'); + }.property('controllers.post.title') + }); + ``` + + @see {Ember.ControllerMixin#needs} + @property {Object} controllers + @default null + */ + controllers: defaultControllersComputedProperty + }); + + __exports__["default"] = ControllerMixin; + }); +define("ember-application/system/application", + ["ember-metal","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/lazy_load","ember-application/system/dag","ember-runtime/system/namespace","ember-runtime/mixins/deferred","ember-application/system/resolver","ember-metal/platform","ember-metal/run_loop","ember-metal/utils","container/container","ember-runtime/controllers/controller","ember-metal/enumerable_utils","ember-runtime/controllers/object_controller","ember-runtime/controllers/array_controller","ember-views/system/event_dispatcher","ember-views/system/jquery","ember-routing/system/route","ember-routing/system/router","ember-routing/location/hash_location","ember-routing/location/history_location","ember-routing/location/auto_location","ember-routing/location/none_location","ember-routing/system/cache","ember-metal/core","ember-handlebars-compiler","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __dependency18__, __dependency19__, __dependency20__, __dependency21__, __dependency22__, __dependency23__, __dependency24__, __dependency25__, __dependency26__, __dependency27__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-application + */ + + var Ember = __dependency1__["default"]; + // Ember.FEATURES, Ember.deprecate, Ember.assert, Ember.libraries, LOG_VERSION, Namespace, BOOTED + var get = __dependency2__.get; + var set = __dependency3__.set; + var runLoadHooks = __dependency4__.runLoadHooks; + var DAG = __dependency5__["default"]; + var Namespace = __dependency6__["default"]; + var DeferredMixin = __dependency7__["default"]; + var DefaultResolver = __dependency8__["default"]; + var create = __dependency9__.create; + var run = __dependency10__["default"]; + var canInvoke = __dependency11__.canInvoke; + var Container = __dependency12__["default"]; + var Controller = __dependency13__["default"]; + var EnumerableUtils = __dependency14__["default"]; + var ObjectController = __dependency15__["default"]; + var ArrayController = __dependency16__["default"]; + var EventDispatcher = __dependency17__["default"]; + //import ContainerDebugAdapter from "ember-extension-support/container_debug_adapter"; + var jQuery = __dependency18__["default"]; + var Route = __dependency19__["default"]; + var Router = __dependency20__["default"]; + var HashLocation = __dependency21__["default"]; + var HistoryLocation = __dependency22__["default"]; + var AutoLocation = __dependency23__["default"]; + var NoneLocation = __dependency24__["default"]; + var BucketCache = __dependency25__["default"]; + + var K = __dependency26__.K; + var EmberHandlebars = __dependency27__["default"]; + + var ContainerDebugAdapter; + + /** + An instance of `Ember.Application` is the starting point for every Ember + application. It helps to instantiate, initialize and coordinate the many + objects that make up your app. + + Each Ember app has one and only one `Ember.Application` object. In fact, the + very first thing you should do in your application is create the instance: + + ```javascript + window.App = Ember.Application.create(); + ``` + + Typically, the application object is the only global variable. All other + classes in your app should be properties on the `Ember.Application` instance, + which highlights its first role: a global namespace. + + For example, if you define a view class, it might look like this: + + ```javascript + App.MyView = Ember.View.extend(); + ``` + + By default, calling `Ember.Application.create()` will automatically initialize + your application by calling the `Ember.Application.initialize()` method. If + you need to delay initialization, you can call your app's `deferReadiness()` + method. When you are ready for your app to be initialized, call its + `advanceReadiness()` method. + + You can define a `ready` method on the `Ember.Application` instance, which + will be run by Ember when the application is initialized. + + Because `Ember.Application` inherits from `Ember.Namespace`, any classes + you create will have useful string representations when calling `toString()`. + See the `Ember.Namespace` documentation for more information. + + While you can think of your `Ember.Application` as a container that holds the + other classes in your application, there are several other responsibilities + going on under-the-hood that you may want to understand. + + ### Event Delegation + + Ember uses a technique called _event delegation_. This allows the framework + to set up a global, shared event listener instead of requiring each view to + do it manually. For example, instead of each view registering its own + `mousedown` listener on its associated element, Ember sets up a `mousedown` + listener on the `body`. + + If a `mousedown` event occurs, Ember will look at the target of the event and + start walking up the DOM node tree, finding corresponding views and invoking + their `mouseDown` method as it goes. + + `Ember.Application` has a number of default events that it listens for, as + well as a mapping from lowercase events to camel-cased view method names. For + example, the `keypress` event causes the `keyPress` method on the view to be + called, the `dblclick` event causes `doubleClick` to be called, and so on. + + If there is a bubbling browser event that Ember does not listen for by + default, you can specify custom events and their corresponding view method + names by setting the application's `customEvents` property: + + ```javascript + App = Ember.Application.create({ + customEvents: { + // add support for the paste event + paste: "paste" + } + }); + ``` + + By default, the application sets up these event listeners on the document + body. However, in cases where you are embedding an Ember application inside + an existing page, you may want it to set up the listeners on an element + inside the body. + + For example, if only events inside a DOM element with the ID of `ember-app` + should be delegated, set your application's `rootElement` property: + + ```javascript + window.App = Ember.Application.create({ + rootElement: '#ember-app' + }); + ``` + + The `rootElement` can be either a DOM element or a jQuery-compatible selector + string. Note that *views appended to the DOM outside the root element will + not receive events.* If you specify a custom root element, make sure you only + append views inside it! + + To learn more about the advantages of event delegation and the Ember view + layer, and a list of the event listeners that are setup by default, visit the + [Ember View Layer guide](http://emberjs.com/guides/understanding-ember/the-view-layer/#toc_event-delegation). + + ### Initializers + + Libraries on top of Ember can add initializers, like so: + + ```javascript + Ember.Application.initializer({ + name: 'api-adapter', + + initialize: function(container, application) { + application.register('api-adapter:main', ApiAdapter); + } + }); + ``` + + Initializers provide an opportunity to access the container, which + organizes the different components of an Ember application. Additionally + they provide a chance to access the instantiated application. Beyond + being used for libraries, initializers are also a great way to organize + dependency injection or setup in your own application. + + ### Routing + + In addition to creating your application's router, `Ember.Application` is + also responsible for telling the router when to start routing. Transitions + between routes can be logged with the `LOG_TRANSITIONS` flag, and more + detailed intra-transition logging can be logged with + the `LOG_TRANSITIONS_INTERNAL` flag: + + ```javascript + window.App = Ember.Application.create({ + LOG_TRANSITIONS: true, // basic logging of successful transitions + LOG_TRANSITIONS_INTERNAL: true // detailed logging of all routing steps + }); + ``` + + By default, the router will begin trying to translate the current URL into + application state once the browser emits the `DOMContentReady` event. If you + need to defer routing, you can call the application's `deferReadiness()` + method. Once routing can begin, call the `advanceReadiness()` method. + + If there is any setup required before routing begins, you can implement a + `ready()` method on your app that will be invoked immediately before routing + begins. + ``` + + @class Application + @namespace Ember + @extends Ember.Namespace + */ + + var Application = Namespace.extend(DeferredMixin, { + _suppressDeferredDeprecation: true, + + /** + The root DOM element of the Application. This can be specified as an + element or a + [jQuery-compatible selector string](http://api.jquery.com/category/selectors/). + + This is the element that will be passed to the Application's, + `eventDispatcher`, which sets up the listeners for event delegation. Every + view in your application should be a child of the element you specify here. + + @property rootElement + @type DOMElement + @default 'body' + */ + rootElement: 'body', + + /** + The `Ember.EventDispatcher` responsible for delegating events to this + application's views. + + The event dispatcher is created by the application at initialization time + and sets up event listeners on the DOM element described by the + application's `rootElement` property. + + See the documentation for `Ember.EventDispatcher` for more information. + + @property eventDispatcher + @type Ember.EventDispatcher + @default null + */ + eventDispatcher: null, + + /** + The DOM events for which the event dispatcher should listen. + + By default, the application's `Ember.EventDispatcher` listens + for a set of standard DOM events, such as `mousedown` and + `keyup`, and delegates them to your application's `Ember.View` + instances. + + If you would like additional bubbling events to be delegated to your + views, set your `Ember.Application`'s `customEvents` property + to a hash containing the DOM event name as the key and the + corresponding view method name as the value. For example: + + ```javascript + App = Ember.Application.create({ + customEvents: { + // add support for the paste event + paste: "paste" + } + }); + ``` + + @property customEvents + @type Object + @default null + */ + customEvents: null, + + // Start off the number of deferrals at 1. This will be + // decremented by the Application's own `initialize` method. + _readinessDeferrals: 1, + + init: function() { + if (!this.$) { this.$ = jQuery; } + this.__container__ = this.buildContainer(); + + this.Router = this.defaultRouter(); + + this._super(); + + this.scheduleInitialize(); + + Ember.libraries.registerCoreLibrary('Handlebars', EmberHandlebars.VERSION); + Ember.libraries.registerCoreLibrary('jQuery', jQuery().jquery); + + if ( Ember.LOG_VERSION ) { + Ember.LOG_VERSION = false; // we only need to see this once per Application#init + + var nameLengths = EnumerableUtils.map(Ember.libraries, function(item) { + return get(item, "name.length"); + }); + + var maxNameLength = Math.max.apply(this, nameLengths); + + Ember.debug('-------------------------------'); + Ember.libraries.each(function(name, version) { + var spaces = new Array(maxNameLength - name.length + 1).join(" "); + Ember.debug([name, spaces, ' : ', version].join("")); + }); + Ember.debug('-------------------------------'); + } + }, + + /** + Build the container for the current application. + + Also register a default application view in case the application + itself does not. + + @private + @method buildContainer + @return {Ember.Container} the configured container + */ + buildContainer: function() { + var container = this.__container__ = Application.buildContainer(this); + + return container; + }, + + /** + If the application has not opted out of routing and has not explicitly + defined a router, supply a default router for the application author + to configure. + + This allows application developers to do: + + ```javascript + var App = Ember.Application.create(); + + App.Router.map(function() { + this.resource('posts'); + }); + ``` + + @private + @method defaultRouter + @return {Ember.Router} the default router + */ + + defaultRouter: function() { + if (this.Router === false) { return; } + var container = this.__container__; + + if (this.Router) { + container.unregister('router:main'); + container.register('router:main', this.Router); + } + + return container.lookupFactory('router:main'); + }, + + /** + Automatically initialize the application once the DOM has + become ready. + + The initialization itself is scheduled on the actions queue + which ensures that application loading finishes before + booting. + + If you are asynchronously loading code, you should call + `deferReadiness()` to defer booting, and then call + `advanceReadiness()` once all of your code has finished + loading. + + @private + @method scheduleInitialize + */ + scheduleInitialize: function() { + var self = this; + + if (!this.$ || this.$.isReady) { + run.schedule('actions', self, '_initialize'); + } else { + this.$().ready(function runInitialize() { + run(self, '_initialize'); + }); + } + }, + + /** + Use this to defer readiness until some condition is true. + + Example: + + ```javascript + App = Ember.Application.create(); + App.deferReadiness(); + + jQuery.getJSON("/auth-token", function(token) { + App.token = token; + App.advanceReadiness(); + }); + ``` + + This allows you to perform asynchronous setup logic and defer + booting your application until the setup has finished. + + However, if the setup requires a loading UI, it might be better + to use the router for this purpose. + + @method deferReadiness + */ + deferReadiness: function() { + Ember.assert("You must call deferReadiness on an instance of Ember.Application", this instanceof Application); + Ember.assert("You cannot defer readiness since the `ready()` hook has already been called.", this._readinessDeferrals > 0); + this._readinessDeferrals++; + }, + + /** + Call `advanceReadiness` after any asynchronous setup logic has completed. + Each call to `deferReadiness` must be matched by a call to `advanceReadiness` + or the application will never become ready and routing will not begin. + + @method advanceReadiness + @see {Ember.Application#deferReadiness} + */ + advanceReadiness: function() { + Ember.assert("You must call advanceReadiness on an instance of Ember.Application", this instanceof Application); + this._readinessDeferrals--; + + if (this._readinessDeferrals === 0) { + run.once(this, this.didBecomeReady); + } + }, + + /** + Registers a factory that can be used for dependency injection (with + `App.inject`) or for service lookup. Each factory is registered with + a full name including two parts: `type:name`. + + A simple example: + + ```javascript + var App = Ember.Application.create(); + App.Orange = Ember.Object.extend(); + App.register('fruit:favorite', App.Orange); + ``` + + Ember will resolve factories from the `App` namespace automatically. + For example `App.CarsController` will be discovered and returned if + an application requests `controller:cars`. + + An example of registering a controller with a non-standard name: + + ```javascript + var App = Ember.Application.create(), + Session = Ember.Controller.extend(); + + App.register('controller:session', Session); + + // The Session controller can now be treated like a normal controller, + // despite its non-standard name. + App.ApplicationController = Ember.Controller.extend({ + needs: ['session'] + }); + ``` + + Registered factories are **instantiated** by having `create` + called on them. Additionally they are **singletons**, each time + they are looked up they return the same instance. + + Some examples modifying that default behavior: + + ```javascript + var App = Ember.Application.create(); + + App.Person = Ember.Object.extend(); + App.Orange = Ember.Object.extend(); + App.Email = Ember.Object.extend(); + App.session = Ember.Object.create(); + + App.register('model:user', App.Person, {singleton: false }); + App.register('fruit:favorite', App.Orange); + App.register('communication:main', App.Email, {singleton: false}); + App.register('session', App.session, {instantiate: false}); + ``` + + @method register + @param fullName {String} type:name (e.g., 'model:user') + @param factory {Function} (e.g., App.Person) + @param options {Object} (optional) disable instantiation or singleton usage + **/ + register: function() { + var container = this.__container__; + container.register.apply(container, arguments); + }, + + /** + Define a dependency injection onto a specific factory or all factories + of a type. + + When Ember instantiates a controller, view, or other framework component + it can attach a dependency to that component. This is often used to + provide services to a set of framework components. + + An example of providing a session object to all controllers: + + ```javascript + var App = Ember.Application.create(), + Session = Ember.Object.extend({ isAuthenticated: false }); + + // A factory must be registered before it can be injected + App.register('session:main', Session); + + // Inject 'session:main' onto all factories of the type 'controller' + // with the name 'session' + App.inject('controller', 'session', 'session:main'); + + App.IndexController = Ember.Controller.extend({ + isLoggedIn: Ember.computed.alias('session.isAuthenticated') + }); + ``` + + Injections can also be performed on specific factories. + + ```javascript + App.inject(, , ) + App.inject('route', 'source', 'source:main') + App.inject('route:application', 'email', 'model:email') + ``` + + It is important to note that injections can only be performed on + classes that are instantiated by Ember itself. Instantiating a class + directly (via `create` or `new`) bypasses the dependency injection + system. + + Ember-Data instantiates its models in a unique manner, and consequently + injections onto models (or all models) will not work as expected. Injections + on models can be enabled by setting `Ember.MODEL_FACTORY_INJECTIONS` + to `true`. + + @method inject + @param factoryNameOrType {String} + @param property {String} + @param injectionName {String} + **/ + inject: function() { + var container = this.__container__; + container.injection.apply(container, arguments); + }, + + /** + Calling initialize manually is not supported. + + Please see Ember.Application#advanceReadiness and + Ember.Application#deferReadiness. + + @private + @deprecated + @method initialize + **/ + initialize: function() { + Ember.deprecate('Calling initialize manually is not supported. Please see Ember.Application#advanceReadiness and Ember.Application#deferReadiness'); + }, + + /** + Initialize the application. This happens automatically. + + Run any initializers and run the application load hook. These hooks may + choose to defer readiness. For example, an authentication hook might want + to defer readiness until the auth token has been retrieved. + + @private + @method _initialize + */ + _initialize: function() { + if (this.isDestroyed) { return; } + + // At this point, the App.Router must already be assigned + if (this.Router) { + var container = this.__container__; + container.unregister('router:main'); + container.register('router:main', this.Router); + } + + this.runInitializers(); + runLoadHooks('application', this); + + // At this point, any initializers or load hooks that would have wanted + // to defer readiness have fired. In general, advancing readiness here + // will proceed to didBecomeReady. + this.advanceReadiness(); + + return this; + }, + + /** + Reset the application. This is typically used only in tests. It cleans up + the application in the following order: + + 1. Deactivate existing routes + 2. Destroy all objects in the container + 3. Create a new application container + 4. Re-route to the existing url + + Typical Example: + + ```javascript + + var App; + + run(function() { + App = Ember.Application.create(); + }); + + module("acceptance test", { + setup: function() { + App.reset(); + } + }); + + test("first test", function() { + // App is freshly reset + }); + + test("first test", function() { + // App is again freshly reset + }); + ``` + + Advanced Example: + + Occasionally you may want to prevent the app from initializing during + setup. This could enable extra configuration, or enable asserting prior + to the app becoming ready. + + ```javascript + + var App; + + run(function() { + App = Ember.Application.create(); + }); + + module("acceptance test", { + setup: function() { + run(function() { + App.reset(); + App.deferReadiness(); + }); + } + }); + + test("first test", function() { + ok(true, 'something before app is initialized'); + + run(function() { + App.advanceReadiness(); + }); + ok(true, 'something after app is initialized'); + }); + ``` + + @method reset + **/ + reset: function() { + this._readinessDeferrals = 1; + + function handleReset() { + var router = this.__container__.lookup('router:main'); + router.reset(); + + run(this.__container__, 'destroy'); + + this.buildContainer(); + + run.schedule('actions', this, function() { + this._initialize(); + }); + } + + run.join(this, handleReset); + }, + + /** + @private + @method runInitializers + */ + runInitializers: function() { + var initializers = get(this.constructor, 'initializers'); + var container = this.__container__; + var graph = new DAG(); + var namespace = this; + var name, initializer; + + for (name in initializers) { + initializer = initializers[name]; + graph.addEdges(initializer.name, initializer.initialize, initializer.before, initializer.after); + } + + graph.topsort(function (vertex) { + var initializer = vertex.value; + Ember.assert("No application initializer named '"+vertex.name+"'", initializer); + initializer(container, namespace); + }); + }, + + /** + @private + @method didBecomeReady + */ + didBecomeReady: function() { + this.setupEventDispatcher(); + this.ready(); // user hook + this.startRouting(); + + if (!Ember.testing) { + // Eagerly name all classes that are already loaded + Ember.Namespace.processAll(); + Ember.BOOTED = true; + } + + this.resolve(this); + }, + + /** + Setup up the event dispatcher to receive events on the + application's `rootElement` with any registered + `customEvents`. + + @private + @method setupEventDispatcher + */ + setupEventDispatcher: function() { + var customEvents = get(this, 'customEvents'); + var rootElement = get(this, 'rootElement'); + var dispatcher = this.__container__.lookup('event_dispatcher:main'); + + set(this, 'eventDispatcher', dispatcher); + dispatcher.setup(customEvents, rootElement); + }, + + /** + If the application has a router, use it to route to the current URL, and + trigger a new call to `route` whenever the URL changes. + + @private + @method startRouting + @property router {Ember.Router} + */ + startRouting: function() { + var router = this.__container__.lookup('router:main'); + if (!router) { return; } + + router.startRouting(); + }, + + handleURL: function(url) { + var router = this.__container__.lookup('router:main'); + + router.handleURL(url); + }, + + /** + Called when the Application has become ready. + The call will be delayed until the DOM has become ready. + + @event ready + */ + ready: K, + + /** + @deprecated Use 'Resolver' instead + Set this to provide an alternate class to `Ember.DefaultResolver` + + + @property resolver + */ + resolver: null, + + /** + Set this to provide an alternate class to `Ember.DefaultResolver` + + @property resolver + */ + Resolver: null, + + willDestroy: function() { + Ember.BOOTED = false; + // Ensure deactivation of routes before objects are destroyed + this.__container__.lookup('router:main').reset(); + + this.__container__.destroy(); + }, + + initializer: function(options) { + this.constructor.initializer(options); + }, + + /** + @method then + @private + @deprecated + */ + then: function() { + Ember.deprecate('Do not use `.then` on an instance of Ember.Application. Please use the `.ready` hook instead.'); + + this._super.apply(this, arguments); + } + }); + + Application.reopenClass({ + initializers: {}, + + /** + Initializer receives an object which has the following attributes: + `name`, `before`, `after`, `initialize`. The only required attribute is + `initialize, all others are optional. + + * `name` allows you to specify under which name the initializer is registered. + This must be a unique name, as trying to register two initializers with the + same name will result in an error. + + ```javascript + Ember.Application.initializer({ + name: 'namedInitializer', + initialize: function(container, application) { + Ember.debug("Running namedInitializer!"); + } + }); + ``` + + * `before` and `after` are used to ensure that this initializer is ran prior + or after the one identified by the value. This value can be a single string + or an array of strings, referencing the `name` of other initializers. + + An example of ordering initializers, we create an initializer named `first`: + + ```javascript + Ember.Application.initializer({ + name: 'first', + initialize: function(container, application) { + Ember.debug("First initializer!"); + } + }); + + // DEBUG: First initializer! + ``` + + We add another initializer named `second`, specifying that it should run + after the initializer named `first`: + + ```javascript + Ember.Application.initializer({ + name: 'second', + after: 'first', + + initialize: function(container, application) { + Ember.debug("Second initializer!"); + } + }); + + // DEBUG: First initializer! + // DEBUG: Second initializer! + ``` + + Afterwards we add a further initializer named `pre`, this time specifying + that it should run before the initializer named `first`: + + ```javascript + Ember.Application.initializer({ + name: 'pre', + before: 'first', + + initialize: function(container, application) { + Ember.debug("Pre initializer!"); + } + }); + + // DEBUG: Pre initializer! + // DEBUG: First initializer! + // DEBUG: Second initializer! + ``` + + Finally we add an initializer named `post`, specifying it should run after + both the `first` and the `second` initializers: + + ```javascript + Ember.Application.initializer({ + name: 'post', + after: ['first', 'second'], + + initialize: function(container, application) { + Ember.debug("Post initializer!"); + } + }); + + // DEBUG: Pre initializer! + // DEBUG: First initializer! + // DEBUG: Second initializer! + // DEBUG: Post initializer! + ``` + + * `initialize` is a callback function that receives two arguments, `container` + and `application` on which you can operate. + + Example of using `container` to preload data into the store: + + ```javascript + Ember.Application.initializer({ + name: "preload-data", + + initialize: function(container, application) { + var store = container.lookup('store:main'); + store.pushPayload(preloadedData); + } + }); + ``` + + Example of using `application` to register an adapter: + + ```javascript + Ember.Application.initializer({ + name: 'api-adapter', + + initialize: function(container, application) { + application.register('api-adapter:main', ApiAdapter); + } + }); + ``` + + @method initializer + @param initializer {Object} + */ + initializer: function(initializer) { + // If this is the first initializer being added to a subclass, we are going to reopen the class + // to make sure we have a new `initializers` object, which extends from the parent class' using + // prototypal inheritance. Without this, attempting to add initializers to the subclass would + // pollute the parent class as well as other subclasses. + if (this.superclass.initializers !== undefined && this.superclass.initializers === this.initializers) { + this.reopenClass({ + initializers: create(this.initializers) + }); + } + + Ember.assert("The initializer '" + initializer.name + "' has already been registered", !this.initializers[initializer.name]); + Ember.assert("An initializer cannot be registered without an initialize function", canInvoke(initializer, 'initialize')); + + this.initializers[initializer.name] = initializer; + }, + + /** + This creates a container with the default Ember naming conventions. + + It also configures the container: + + * registered views are created every time they are looked up (they are + not singletons) + * registered templates are not factories; the registered value is + returned directly. + * the router receives the application as its `namespace` property + * all controllers receive the router as their `target` and `controllers` + properties + * all controllers receive the application as their `namespace` property + * the application view receives the application controller as its + `controller` property + * the application view receives the application template as its + `defaultTemplate` property + + @private + @method buildContainer + @static + @param {Ember.Application} namespace the application to build the + container for. + @return {Ember.Container} the built container + */ + buildContainer: function(namespace) { + var container = new Container(); + + container.set = set; + container.resolver = resolverFor(namespace); + container.normalize = container.resolver.normalize; + container.describe = container.resolver.describe; + container.makeToString = container.resolver.makeToString; + + container.optionsForType('component', { singleton: false }); + container.optionsForType('view', { singleton: false }); + container.optionsForType('template', { instantiate: false }); + container.optionsForType('helper', { instantiate: false }); + + container.register('application:main', namespace, { instantiate: false }); + + container.register('controller:basic', Controller, { instantiate: false }); + container.register('controller:object', ObjectController, { instantiate: false }); + container.register('controller:array', ArrayController, { instantiate: false }); + container.register('route:basic', Route, { instantiate: false }); + container.register('event_dispatcher:main', EventDispatcher); + + container.register('router:main', Router); + container.injection('router:main', 'namespace', 'application:main'); + + container.register('location:auto', AutoLocation); + container.register('location:hash', HashLocation); + container.register('location:history', HistoryLocation); + container.register('location:none', NoneLocation); + + container.injection('controller', 'target', 'router:main'); + container.injection('controller', 'namespace', 'application:main'); + + container.register('-bucket-cache:main', BucketCache); + container.injection('router', '_bucketCache', '-bucket-cache:main'); + container.injection('route', '_bucketCache', '-bucket-cache:main'); + container.injection('controller', '_bucketCache', '-bucket-cache:main'); + + container.injection('route', 'router', 'router:main'); + container.injection('location', 'rootURL', '-location-setting:root-url'); + + // DEBUGGING + container.register('resolver-for-debugging:main', container.resolver.__resolver__, { instantiate: false }); + container.injection('container-debug-adapter:main', 'resolver', 'resolver-for-debugging:main'); + container.injection('data-adapter:main', 'containerDebugAdapter', 'container-debug-adapter:main'); + // Custom resolver authors may want to register their own ContainerDebugAdapter with this key + + // ES6TODO: resolve this via import once ember-application package is ES6'ed + if (!ContainerDebugAdapter) { ContainerDebugAdapter = requireModule('ember-extension-support/container_debug_adapter')['default']; } + container.register('container-debug-adapter:main', ContainerDebugAdapter); + + return container; + } + }); + + /** + This function defines the default lookup rules for container lookups: + + * templates are looked up on `Ember.TEMPLATES` + * other names are looked up on the application after classifying the name. + For example, `controller:post` looks up `App.PostController` by default. + * if the default lookup fails, look for registered classes on the container + + This allows the application to register default injections in the container + that could be overridden by the normal naming convention. + + @private + @method resolverFor + @param {Ember.Namespace} namespace the namespace to look for classes + @return {*} the resolved value for a given lookup + */ + function resolverFor(namespace) { + if (namespace.get('resolver')) { + Ember.deprecate('Application.resolver is deprecated in favor of Application.Resolver', false); + } + + var ResolverClass = namespace.get('resolver') || namespace.get('Resolver') || DefaultResolver; + var resolver = ResolverClass.create({ + namespace: namespace + }); + + function resolve(fullName) { + return resolver.resolve(fullName); + } + + resolve.describe = function(fullName) { + return resolver.lookupDescription(fullName); + }; + + resolve.makeToString = function(factory, fullName) { + return resolver.makeToString(factory, fullName); + }; + + resolve.normalize = function(fullName) { + if (resolver.normalize) { + return resolver.normalize(fullName); + } else { + Ember.deprecate('The Resolver should now provide a \'normalize\' function', false); + return fullName; + } + }; + + resolve.__resolver__ = resolver; + + return resolve; + } + + __exports__["default"] = Application; + }); +define("ember-application/system/dag", + ["ember-metal/error","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var EmberError = __dependency1__["default"]; + + function visit(vertex, fn, visited, path) { + var name = vertex.name; + var vertices = vertex.incoming; + var names = vertex.incomingNames; + var len = names.length; + var i; + + if (!visited) { + visited = {}; + } + if (!path) { + path = []; + } + if (visited.hasOwnProperty(name)) { + return; + } + path.push(name); + visited[name] = true; + for (i = 0; i < len; i++) { + visit(vertices[names[i]], fn, visited, path); + } + fn(vertex, path); + path.pop(); + } + + + /** + * DAG stands for Directed acyclic graph. + * + * It is used to build a graph of dependencies checking that there isn't circular + * dependencies. p.e Registering initializers with a certain precedence order. + * + * @class DAG + * @constructor + */ + function DAG() { + this.names = []; + this.vertices = {}; + } + + /** + * Adds a vertex entry to the graph unless it is already added. + * + * @private + * @method add + * @param {String} name The name of the vertex to add + */ + DAG.prototype.add = function(name) { + if (!name) { return; } + if (this.vertices.hasOwnProperty(name)) { + return this.vertices[name]; + } + var vertex = { + name: name, incoming: {}, incomingNames: [], hasOutgoing: false, value: null + }; + this.vertices[name] = vertex; + this.names.push(name); + return vertex; + }; + + /** + * Adds a vertex to the graph and sets its value. + * + * @private + * @method map + * @param {String} name The name of the vertex. + * @param value The value to put in the vertex. + */ + DAG.prototype.map = function(name, value) { + this.add(name).value = value; + }; + + /** + * Connects the vertices with the given names, adding them to the graph if + * necesary, only if this does not produce is any circular dependency. + * + * @private + * @method addEdge + * @param {String} fromName The name the vertex where the edge starts. + * @param {String} toName The name the vertex where the edge ends. + */ + DAG.prototype.addEdge = function(fromName, toName) { + if (!fromName || !toName || fromName === toName) { + return; + } + var from = this.add(fromName), to = this.add(toName); + if (to.incoming.hasOwnProperty(fromName)) { + return; + } + function checkCycle(vertex, path) { + if (vertex.name === toName) { + throw new EmberError("cycle detected: " + toName + " <- " + path.join(" <- ")); + } + } + visit(from, checkCycle); + from.hasOutgoing = true; + to.incoming[fromName] = from; + to.incomingNames.push(fromName); + }; + + /** + * Visits all the vertex of the graph calling the given function with each one, + * ensuring that the vertices are visited respecting their precedence. + * + * @method topsort + * @param {Function} fn The function to be invoked on each vertex. + */ + DAG.prototype.topsort = function(fn) { + var visited = {}; + var vertices = this.vertices; + var names = this.names; + var len = names.length; + var i, vertex; + + for (i = 0; i < len; i++) { + vertex = vertices[names[i]]; + if (!vertex.hasOutgoing) { + visit(vertex, fn, visited); + } + } + }; + + /** + * Adds a vertex with the given name and value to the graph and joins it with the + * vertices referenced in _before_ and _after_. If there isn't vertices with those + * names, they are added too. + * + * If either _before_ or _after_ are falsy/empty, the added vertex will not have + * an incoming/outgoing edge. + * + * @method addEdges + * @param {String} name The name of the vertex to be added. + * @param value The value of that vertex. + * @param before An string or array of strings with the names of the vertices before + * which this vertex must be visited. + * @param after An string or array of strings with the names of the vertex after + * which this vertex must be visited. + * + */ + DAG.prototype.addEdges = function(name, value, before, after) { + var i; + this.map(name, value); + if (before) { + if (typeof before === 'string') { + this.addEdge(name, before); + } else { + for (i = 0; i < before.length; i++) { + this.addEdge(name, before[i]); + } + } + } + if (after) { + if (typeof after === 'string') { + this.addEdge(after, name); + } else { + for (i = 0; i < after.length; i++) { + this.addEdge(after[i], name); + } + } + } + }; + + __exports__["default"] = DAG; + }); +define("ember-application/system/resolver", + ["ember-metal/core","ember-metal/property_get","ember-metal/logger","ember-runtime/system/string","ember-runtime/system/object","ember-runtime/system/namespace","ember-handlebars","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-application + */ + + var Ember = __dependency1__["default"]; + // Ember.TEMPLATES, Ember.assert + var get = __dependency2__.get; + var Logger = __dependency3__["default"]; + var classify = __dependency4__.classify; + var capitalize = __dependency4__.capitalize; + var decamelize = __dependency4__.decamelize; + var EmberObject = __dependency5__["default"]; + var Namespace = __dependency6__["default"]; + var EmberHandlebars = __dependency7__["default"]; + + var Resolver = EmberObject.extend({ + /** + This will be set to the Application instance when it is + created. + + @property namespace + */ + namespace: null, + normalize: Ember.required(Function), + resolve: Ember.required(Function), + parseName: Ember.required(Function), + lookupDescription: Ember.required(Function), + makeToString: Ember.required(Function), + resolveOther: Ember.required(Function), + _logLookup: Ember.required(Function) + }); + __exports__.Resolver = Resolver; + /** + The DefaultResolver defines the default lookup rules to resolve + container lookups before consulting the container for registered + items: + + * templates are looked up on `Ember.TEMPLATES` + * other names are looked up on the application after converting + the name. For example, `controller:post` looks up + `App.PostController` by default. + * there are some nuances (see examples below) + + ### How Resolving Works + + The container calls this object's `resolve` method with the + `fullName` argument. + + It first parses the fullName into an object using `parseName`. + + Then it checks for the presence of a type-specific instance + method of the form `resolve[Type]` and calls it if it exists. + For example if it was resolving 'template:post', it would call + the `resolveTemplate` method. + + Its last resort is to call the `resolveOther` method. + + The methods of this object are designed to be easy to override + in a subclass. For example, you could enhance how a template + is resolved like so: + + ```javascript + App = Ember.Application.create({ + Resolver: Ember.DefaultResolver.extend({ + resolveTemplate: function(parsedName) { + var resolvedTemplate = this._super(parsedName); + if (resolvedTemplate) { return resolvedTemplate; } + return Ember.TEMPLATES['not_found']; + } + }) + }); + ``` + + Some examples of how names are resolved: + + ``` + 'template:post' //=> Ember.TEMPLATES['post'] + 'template:posts/byline' //=> Ember.TEMPLATES['posts/byline'] + 'template:posts.byline' //=> Ember.TEMPLATES['posts/byline'] + 'template:blogPost' //=> Ember.TEMPLATES['blogPost'] + // OR + // Ember.TEMPLATES['blog_post'] + 'controller:post' //=> App.PostController + 'controller:posts.index' //=> App.PostsIndexController + 'controller:blog/post' //=> Blog.PostController + 'controller:basic' //=> Ember.Controller + 'route:post' //=> App.PostRoute + 'route:posts.index' //=> App.PostsIndexRoute + 'route:blog/post' //=> Blog.PostRoute + 'route:basic' //=> Ember.Route + 'view:post' //=> App.PostView + 'view:posts.index' //=> App.PostsIndexView + 'view:blog/post' //=> Blog.PostView + 'view:basic' //=> Ember.View + 'foo:post' //=> App.PostFoo + 'model:post' //=> App.Post + ``` + + @class DefaultResolver + @namespace Ember + @extends Ember.Object + */ + + __exports__["default"] = EmberObject.extend({ + /** + This will be set to the Application instance when it is + created. + + @property namespace + */ + namespace: null, + + normalize: function(fullName) { + var split = fullName.split(':', 2), + type = split[0], + name = split[1]; + + Ember.assert("Tried to normalize a container name without a colon (:) in it. You probably tried to lookup a name that did not contain a type, a colon, and a name. A proper lookup name would be `view:post`.", split.length === 2); + + if (type !== 'template') { + var result = name; + + if (result.indexOf('.') > -1) { + result = result.replace(/\.(.)/g, function(m) { return m.charAt(1).toUpperCase(); }); + } + + if (name.indexOf('_') > -1) { + result = result.replace(/_(.)/g, function(m) { return m.charAt(1).toUpperCase(); }); + } + + return type + ':' + result; + } else { + return fullName; + } + }, + + + /** + This method is called via the container's resolver method. + It parses the provided `fullName` and then looks up and + returns the appropriate template or class. + + @method resolve + @param {String} fullName the lookup string + @return {Object} the resolved factory + */ + resolve: function(fullName) { + var parsedName = this.parseName(fullName), + resolveMethodName = parsedName.resolveMethodName, + resolved; + + if (!(parsedName.name && parsedName.type)) { + throw new TypeError('Invalid fullName: `' + fullName + '`, must be of the form `type:name` '); + } + + if (this[resolveMethodName]) { + resolved = this[resolveMethodName](parsedName); + } + + if (!resolved) { + resolved = this.resolveOther(parsedName); + } + + if (parsedName.root && parsedName.root.LOG_RESOLVER) { + this._logLookup(resolved, parsedName); + } + + return resolved; + }, + /** + Convert the string name of the form 'type:name' to + a Javascript object with the parsed aspects of the name + broken out. + + @protected + @param {String} fullName the lookup string + @method parseName + */ + parseName: function(fullName) { + var nameParts = fullName.split(':'), + type = nameParts[0], fullNameWithoutType = nameParts[1], + name = fullNameWithoutType, + namespace = get(this, 'namespace'), + root = namespace; + + if (type !== 'template' && name.indexOf('/') !== -1) { + var parts = name.split('/'); + name = parts[parts.length - 1]; + var namespaceName = capitalize(parts.slice(0, -1).join('.')); + root = Namespace.byName(namespaceName); + + Ember.assert('You are looking for a ' + name + ' ' + type + ' in the ' + namespaceName + ' namespace, but the namespace could not be found', root); + } + + return { + fullName: fullName, + type: type, + fullNameWithoutType: fullNameWithoutType, + name: name, + root: root, + resolveMethodName: 'resolve' + classify(type) + }; + }, + + /** + Returns a human-readable description for a fullName. Used by the + Application namespace in assertions to describe the + precise name of the class that Ember is looking for, rather than + container keys. + + @protected + @param {String} fullName the lookup string + @method lookupDescription + */ + lookupDescription: function(fullName) { + var parsedName = this.parseName(fullName); + + if (parsedName.type === 'template') { + return 'template at ' + parsedName.fullNameWithoutType.replace(/\./g, '/'); + } + + var description = parsedName.root + '.' + classify(parsedName.name); + if (parsedName.type !== 'model') { description += classify(parsedName.type); } + + return description; + }, + + makeToString: function(factory, fullName) { + return factory.toString(); + }, + /** + Given a parseName object (output from `parseName`), apply + the conventions expected by `Ember.Router` + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method useRouterNaming + */ + useRouterNaming: function(parsedName) { + parsedName.name = parsedName.name.replace(/\./g, '_'); + if (parsedName.name === 'basic') { + parsedName.name = ''; + } + }, + /** + Look up the template in Ember.TEMPLATES + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveTemplate + */ + resolveTemplate: function(parsedName) { + var templateName = parsedName.fullNameWithoutType.replace(/\./g, '/'); + + if (Ember.TEMPLATES[templateName]) { + return Ember.TEMPLATES[templateName]; + } + + templateName = decamelize(templateName); + if (Ember.TEMPLATES[templateName]) { + return Ember.TEMPLATES[templateName]; + } + }, + /** + Lookup the view using `resolveOther` + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveView + */ + resolveView: function(parsedName) { + this.useRouterNaming(parsedName); + return this.resolveOther(parsedName); + }, + /** + Lookup the controller using `resolveOther` + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveController + */ + resolveController: function(parsedName) { + this.useRouterNaming(parsedName); + return this.resolveOther(parsedName); + }, + /** + Lookup the route using `resolveOther` + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveRoute + */ + resolveRoute: function(parsedName) { + this.useRouterNaming(parsedName); + return this.resolveOther(parsedName); + }, + + /** + Lookup the model on the Application namespace + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveModel + */ + resolveModel: function(parsedName) { + var className = classify(parsedName.name); + var factory = get(parsedName.root, className); + + if (factory) { return factory; } + }, + /** + Look up the specified object (from parsedName) on the appropriate + namespace (usually on the Application) + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveHelper + */ + resolveHelper: function(parsedName) { + return this.resolveOther(parsedName) || EmberHandlebars.helpers[parsedName.fullNameWithoutType]; + }, + /** + Look up the specified object (from parsedName) on the appropriate + namespace (usually on the Application) + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveOther + */ + resolveOther: function(parsedName) { + var className = classify(parsedName.name) + classify(parsedName.type); + var factory = get(parsedName.root, className); + if (factory) { return factory; } + }, + + /** + @method _logLookup + @param {Boolean} found + @param {Object} parsedName + @private + */ + _logLookup: function(found, parsedName) { + var symbol, padding; + + if (found) { symbol = '[✓]'; } + else { symbol = '[ ]'; } + + if (parsedName.fullName.length > 60) { + padding = '.'; + } else { + padding = new Array(60 - parsedName.fullName.length).join('.'); + } + + Logger.info(symbol, parsedName.fullName, padding, this.lookupDescription(parsedName.fullName)); + } + }); + }); +define("ember-debug", + ["ember-metal/core","ember-metal/error","ember-metal/logger"], + function(__dependency1__, __dependency2__, __dependency3__) { + "use strict"; + /*global __fail__*/ + + var Ember = __dependency1__["default"]; + var EmberError = __dependency2__["default"]; + var Logger = __dependency3__["default"]; + + /** + Ember Debug + + @module ember + @submodule ember-debug + */ + + /** + @class Ember + */ + + /** + Define an assertion that will throw an exception if the condition is not + met. Ember build tools will remove any calls to `Ember.assert()` when + doing a production build. Example: + + ```javascript + // Test for truthiness + Ember.assert('Must pass a valid object', obj); + + // Fail unconditionally + Ember.assert('This code path should never be run'); + ``` + + @method assert + @param {String} desc A description of the assertion. This will become + the text of the Error thrown if the assertion fails. + @param {Boolean} test Must be truthy for the assertion to pass. If + falsy, an exception will be thrown. + */ + Ember.assert = function(desc, test) { + if (!test) { + throw new EmberError("Assertion Failed: " + desc); + } + }; + + + /** + Display a warning with the provided message. Ember build tools will + remove any calls to `Ember.warn()` when doing a production build. + + @method warn + @param {String} message A warning to display. + @param {Boolean} test An optional boolean. If falsy, the warning + will be displayed. + */ + Ember.warn = function(message, test) { + if (!test) { + Logger.warn("WARNING: "+message); + if ('trace' in Logger) Logger.trace(); + } + }; + + /** + Display a debug notice. Ember build tools will remove any calls to + `Ember.debug()` when doing a production build. + + ```javascript + Ember.debug('I\'m a debug notice!'); + ``` + + @method debug + @param {String} message A debug message to display. + */ + Ember.debug = function(message) { + Logger.debug("DEBUG: "+message); + }; + + /** + Display a deprecation warning with the provided message and a stack trace + (Chrome and Firefox only). Ember build tools will remove any calls to + `Ember.deprecate()` when doing a production build. + + @method deprecate + @param {String} message A description of the deprecation. + @param {Boolean} test An optional boolean. If falsy, the deprecation + will be displayed. + */ + Ember.deprecate = function(message, test) { + if (test) { return; } + + if (Ember.ENV.RAISE_ON_DEPRECATION) { throw new EmberError(message); } + + var error; + + // When using new Error, we can't do the arguments check for Chrome. Alternatives are welcome + try { __fail__.fail(); } catch (e) { error = e; } + + if (Ember.LOG_STACKTRACE_ON_DEPRECATION && error.stack) { + var stack, stackStr = ''; + if (error['arguments']) { + // Chrome + stack = error.stack.replace(/^\s+at\s+/gm, ''). + replace(/^([^\(]+?)([\n$])/gm, '{anonymous}($1)$2'). + replace(/^Object.\s*\(([^\)]+)\)/gm, '{anonymous}($1)').split('\n'); + stack.shift(); + } else { + // Firefox + stack = error.stack.replace(/(?:\n@:0)?\s+$/m, ''). + replace(/^\(/gm, '{anonymous}(').split('\n'); + } + + stackStr = "\n " + stack.slice(2).join("\n "); + message = message + stackStr; + } + + Logger.warn("DEPRECATION: "+message); + }; + + + + /** + Alias an old, deprecated method with its new counterpart. + + Display a deprecation warning with the provided message and a stack trace + (Chrome and Firefox only) when the assigned method is called. + + Ember build tools will not remove calls to `Ember.deprecateFunc()`, though + no warnings will be shown in production. + + ```javascript + Ember.oldMethod = Ember.deprecateFunc('Please use the new, updated method', Ember.newMethod); + ``` + + @method deprecateFunc + @param {String} message A description of the deprecation. + @param {Function} func The new function called to replace its deprecated counterpart. + @return {Function} a new function that wrapped the original function with a deprecation warning + */ + Ember.deprecateFunc = function(message, func) { + return function() { + Ember.deprecate(message); + return func.apply(this, arguments); + }; + }; + + + /** + Run a function meant for debugging. Ember build tools will remove any calls to + `Ember.runInDebug()` when doing a production build. + + ```javascript + Ember.runInDebug(function() { + Ember.Handlebars.EachView.reopen({ + didInsertElement: function() { + console.log('I\'m happy'); + } + }); + }); + ``` + + @method runInDebug + @param {Function} func The function to be executed. + @since 1.5.0 + */ + Ember.runInDebug = function(func) { + func(); + }; + + // Inform the developer about the Ember Inspector if not installed. + if (!Ember.testing) { + var isFirefox = typeof InstallTrigger !== 'undefined'; + var isChrome = !!window.chrome && !window.opera; + + if (typeof window !== 'undefined' && (isFirefox || isChrome) && window.addEventListener) { + window.addEventListener("load", function() { + if (document.documentElement && document.documentElement.dataset && !document.documentElement.dataset.emberExtension) { + var downloadURL; + + if(isChrome) { + downloadURL = 'https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi'; + } else if(isFirefox) { + downloadURL = 'https://addons.mozilla.org/en-US/firefox/addon/ember-inspector/'; + } + + Ember.debug('For more advanced debugging, install the Ember Inspector from ' + downloadURL); + } + }, false); + } + } + }); +define("ember-extension-support", + ["ember-metal/core","ember-extension-support/data_adapter","ember-extension-support/container_debug_adapter"], + function(__dependency1__, __dependency2__, __dependency3__) { + "use strict"; + /** + Ember Extension Support + + @module ember + @submodule ember-extension-support + @requires ember-application + */ + + var Ember = __dependency1__["default"]; + var DataAdapter = __dependency2__["default"]; + var ContainerDebugAdapter = __dependency3__["default"]; + + Ember.DataAdapter = DataAdapter; + Ember.ContainerDebugAdapter = ContainerDebugAdapter; + }); +define("ember-extension-support/container_debug_adapter", + ["ember-metal/core","ember-runtime/system/native_array","ember-metal/utils","ember-runtime/system/string","ember-runtime/system/namespace","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var emberA = __dependency2__.A; + var typeOf = __dependency3__.typeOf; + var dasherize = __dependency4__.dasherize; + var classify = __dependency4__.classify; + var Namespace = __dependency5__["default"]; + var EmberObject = __dependency6__["default"]; + + /** + @module ember + @submodule ember-extension-support + */ + + /** + The `ContainerDebugAdapter` helps the container and resolver interface + with tools that debug Ember such as the + [Ember Extension](https://github.com/tildeio/ember-extension) + for Chrome and Firefox. + + This class can be extended by a custom resolver implementer + to override some of the methods with library-specific code. + + The methods likely to be overridden are: + + * `canCatalogEntriesByType` + * `catalogEntriesByType` + + The adapter will need to be registered + in the application's container as `container-debug-adapter:main` + + Example: + + ```javascript + Application.initializer({ + name: "containerDebugAdapter", + + initialize: function(container, application) { + application.register('container-debug-adapter:main', require('app/container-debug-adapter')); + } + }); + ``` + + @class ContainerDebugAdapter + @namespace Ember + @extends EmberObject + @since 1.5.0 + */ + __exports__["default"] = EmberObject.extend({ + /** + The container of the application being debugged. + This property will be injected + on creation. + + @property container + @default null + */ + container: null, + + /** + The resolver instance of the application + being debugged. This property will be injected + on creation. + + @property resolver + @default null + */ + resolver: null, + + /** + Returns true if it is possible to catalog a list of available + classes in the resolver for a given type. + + @method canCatalogEntriesByType + @param {string} type The type. e.g. "model", "controller", "route" + @return {boolean} whether a list is available for this type. + */ + canCatalogEntriesByType: function(type) { + if (type === 'model' || type === 'template') return false; + return true; + }, + + /** + Returns the available classes a given type. + + @method catalogEntriesByType + @param {string} type The type. e.g. "model", "controller", "route" + @return {Array} An array of strings. + */ + catalogEntriesByType: function(type) { + var namespaces = emberA(Namespace.NAMESPACES), types = emberA(), self = this; + var typeSuffixRegex = new RegExp(classify(type) + "$"); + + namespaces.forEach(function(namespace) { + if (namespace !== Ember) { + for (var key in namespace) { + if (!namespace.hasOwnProperty(key)) { continue; } + if (typeSuffixRegex.test(key)) { + var klass = namespace[key]; + if (typeOf(klass) === 'class') { + types.push(dasherize(key.replace(typeSuffixRegex, ''))); + } + } + } + } + }); + return types; + } + }); + }); +define("ember-extension-support/data_adapter", + ["ember-metal/core","ember-metal/property_get","ember-metal/run_loop","ember-runtime/system/string","ember-runtime/system/namespace","ember-runtime/system/object","ember-runtime/system/native_array","ember-application/system/application","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var get = __dependency2__.get; + var run = __dependency3__["default"]; + var dasherize = __dependency4__.dasherize; + var Namespace = __dependency5__["default"]; + var EmberObject = __dependency6__["default"]; + var emberA = __dependency7__.A; + var Application = __dependency8__["default"]; + + /** + @module ember + @submodule ember-extension-support + */ + + /** + The `DataAdapter` helps a data persistence library + interface with tools that debug Ember such + as the [Ember Extension](https://github.com/tildeio/ember-extension) + for Chrome and Firefox. + + This class will be extended by a persistence library + which will override some of the methods with + library-specific code. + + The methods likely to be overridden are: + + * `getFilters` + * `detect` + * `columnsForType` + * `getRecords` + * `getRecordColumnValues` + * `getRecordKeywords` + * `getRecordFilterValues` + * `getRecordColor` + * `observeRecord` + + The adapter will need to be registered + in the application's container as `dataAdapter:main` + + Example: + + ```javascript + Application.initializer({ + name: "data-adapter", + + initialize: function(container, application) { + application.register('data-adapter:main', DS.DataAdapter); + } + }); + ``` + + @class DataAdapter + @namespace Ember + @extends EmberObject + */ + __exports__["default"] = EmberObject.extend({ + init: function() { + this._super(); + this.releaseMethods = emberA(); + }, + + /** + The container of the application being debugged. + This property will be injected + on creation. + + @property container + @default null + @since 1.3.0 + */ + container: null, + + + /** + The container-debug-adapter which is used + to list all models. + + @property containerDebugAdapter + @default undefined + @since 1.5.0 + **/ + containerDebugAdapter: undefined, + + /** + Number of attributes to send + as columns. (Enough to make the record + identifiable). + + @private + @property attributeLimit + @default 3 + @since 1.3.0 + */ + attributeLimit: 3, + + /** + Stores all methods that clear observers. + These methods will be called on destruction. + + @private + @property releaseMethods + @since 1.3.0 + */ + releaseMethods: emberA(), + + /** + Specifies how records can be filtered. + Records returned will need to have a `filterValues` + property with a key for every name in the returned array. + + @public + @method getFilters + @return {Array} List of objects defining filters. + The object should have a `name` and `desc` property. + */ + getFilters: function() { + return emberA(); + }, + + /** + Fetch the model types and observe them for changes. + + @public + @method watchModelTypes + + @param {Function} typesAdded Callback to call to add types. + Takes an array of objects containing wrapped types (returned from `wrapModelType`). + + @param {Function} typesUpdated Callback to call when a type has changed. + Takes an array of objects containing wrapped types. + + @return {Function} Method to call to remove all observers + */ + watchModelTypes: function(typesAdded, typesUpdated) { + var modelTypes = this.getModelTypes(), + self = this, typesToSend, releaseMethods = emberA(); + + typesToSend = modelTypes.map(function(type) { + var klass = type.klass; + var wrapped = self.wrapModelType(klass, type.name); + releaseMethods.push(self.observeModelType(klass, typesUpdated)); + return wrapped; + }); + + typesAdded(typesToSend); + + var release = function() { + releaseMethods.forEach(function(fn) { fn(); }); + self.releaseMethods.removeObject(release); + }; + this.releaseMethods.pushObject(release); + return release; + }, + + _nameToClass: function(type) { + if (typeof type === 'string') { + type = this.container.lookupFactory('model:' + type); + } + return type; + }, + + /** + Fetch the records of a given type and observe them for changes. + + @public + @method watchRecords + + @param {Function} recordsAdded Callback to call to add records. + Takes an array of objects containing wrapped records. + The object should have the following properties: + columnValues: {Object} key and value of a table cell + object: {Object} the actual record object + + @param {Function} recordsUpdated Callback to call when a record has changed. + Takes an array of objects containing wrapped records. + + @param {Function} recordsRemoved Callback to call when a record has removed. + Takes the following parameters: + index: the array index where the records were removed + count: the number of records removed + + @return {Function} Method to call to remove all observers + */ + watchRecords: function(type, recordsAdded, recordsUpdated, recordsRemoved) { + var self = this, releaseMethods = emberA(), records = this.getRecords(type), release; + + var recordUpdated = function(updatedRecord) { + recordsUpdated([updatedRecord]); + }; + + var recordsToSend = records.map(function(record) { + releaseMethods.push(self.observeRecord(record, recordUpdated)); + return self.wrapRecord(record); + }); + + + var contentDidChange = function(array, idx, removedCount, addedCount) { + for (var i = idx; i < idx + addedCount; i++) { + var record = array.objectAt(i); + var wrapped = self.wrapRecord(record); + releaseMethods.push(self.observeRecord(record, recordUpdated)); + recordsAdded([wrapped]); + } + + if (removedCount) { + recordsRemoved(idx, removedCount); + } + }; + + var observer = { didChange: contentDidChange, willChange: Ember.K }; + records.addArrayObserver(self, observer); + + release = function() { + releaseMethods.forEach(function(fn) { fn(); }); + records.removeArrayObserver(self, observer); + self.releaseMethods.removeObject(release); + }; + + recordsAdded(recordsToSend); + + this.releaseMethods.pushObject(release); + return release; + }, + + /** + Clear all observers before destruction + @private + @method willDestroy + */ + willDestroy: function() { + this._super(); + this.releaseMethods.forEach(function(fn) { + fn(); + }); + }, + + /** + Detect whether a class is a model. + + Test that against the model class + of your persistence library + + @private + @method detect + @param {Class} klass The class to test + @return boolean Whether the class is a model class or not + */ + detect: function(klass) { + return false; + }, + + /** + Get the columns for a given model type. + + @private + @method columnsForType + @param {Class} type The model type + @return {Array} An array of columns of the following format: + name: {String} name of the column + desc: {String} Humanized description (what would show in a table column name) + */ + columnsForType: function(type) { + return emberA(); + }, + + /** + Adds observers to a model type class. + + @private + @method observeModelType + @param {Class} type The model type class + @param {Function} typesUpdated Called when a type is modified. + @return {Function} The function to call to remove observers + */ + + observeModelType: function(type, typesUpdated) { + var self = this, records = this.getRecords(type); + + var onChange = function() { + typesUpdated([self.wrapModelType(type)]); + }; + var observer = { + didChange: function() { + run.scheduleOnce('actions', this, onChange); + }, + willChange: Ember.K + }; + + records.addArrayObserver(this, observer); + + var release = function() { + records.removeArrayObserver(self, observer); + }; + + return release; + }, + + + /** + Wraps a given model type and observes changes to it. + + @private + @method wrapModelType + @param {Class} type A model class + @param {String} Optional name of the class + @return {Object} contains the wrapped type and the function to remove observers + Format: + type: {Object} the wrapped type + The wrapped type has the following format: + name: {String} name of the type + count: {Integer} number of records available + columns: {Columns} array of columns to describe the record + object: {Class} the actual Model type class + release: {Function} The function to remove observers + */ + wrapModelType: function(type, name) { + var release, records = this.getRecords(type), + typeToSend, self = this; + + typeToSend = { + name: name || type.toString(), + count: get(records, 'length'), + columns: this.columnsForType(type), + object: type + }; + + + return typeToSend; + }, + + + /** + Fetches all models defined in the application. + + @private + @method getModelTypes + @return {Array} Array of model types + */ + getModelTypes: function() { + var types, self = this, + containerDebugAdapter = this.get('containerDebugAdapter'); + + if (containerDebugAdapter.canCatalogEntriesByType('model')) { + types = containerDebugAdapter.catalogEntriesByType('model'); + } else { + types = this._getObjectsOnNamespaces(); + } + + // New adapters return strings instead of classes + types = emberA(types).map(function(name) { + return { + klass: self._nameToClass(name), + name: name + }; + }); + types = emberA(types).filter(function(type) { + return self.detect(type.klass); + }); + + return emberA(types); + }, + + /** + Loops over all namespaces and all objects + attached to them + + @private + @method _getObjectsOnNamespaces + @return {Array} Array of model type strings + */ + _getObjectsOnNamespaces: function() { + var namespaces = emberA(Namespace.NAMESPACES), + types = emberA(), + self = this; + + namespaces.forEach(function(namespace) { + for (var key in namespace) { + if (!namespace.hasOwnProperty(key)) { continue; } + // Even though we will filter again in `getModelTypes`, + // we should not call `lookupContainer` on non-models + // (especially when `Ember.MODEL_FACTORY_INJECTIONS` is `true`) + if (!self.detect(namespace[key])) { continue; } + var name = dasherize(key); + if (!(namespace instanceof Application) && namespace.toString()) { + name = namespace + '/' + name; + } + types.push(name); + } + }); + return types; + }, + + /** + Fetches all loaded records for a given type. + + @private + @method getRecords + @return {Array} An array of records. + This array will be observed for changes, + so it should update when new records are added/removed. + */ + getRecords: function(type) { + return emberA(); + }, + + /** + Wraps a record and observers changes to it. + + @private + @method wrapRecord + @param {Object} record The record instance. + @return {Object} The wrapped record. Format: + columnValues: {Array} + searchKeywords: {Array} + */ + wrapRecord: function(record) { + var recordToSend = { object: record }, columnValues = {}, self = this; + + recordToSend.columnValues = this.getRecordColumnValues(record); + recordToSend.searchKeywords = this.getRecordKeywords(record); + recordToSend.filterValues = this.getRecordFilterValues(record); + recordToSend.color = this.getRecordColor(record); + + return recordToSend; + }, + + /** + Gets the values for each column. + + @private + @method getRecordColumnValues + @return {Object} Keys should match column names defined + by the model type. + */ + getRecordColumnValues: function(record) { + return {}; + }, + + /** + Returns keywords to match when searching records. + + @private + @method getRecordKeywords + @return {Array} Relevant keywords for search. + */ + getRecordKeywords: function(record) { + return emberA(); + }, + + /** + Returns the values of filters defined by `getFilters`. + + @private + @method getRecordFilterValues + @param {Object} record The record instance + @return {Object} The filter values + */ + getRecordFilterValues: function(record) { + return {}; + }, + + /** + Each record can have a color that represents its state. + + @private + @method getRecordColor + @param {Object} record The record instance + @return {String} The record's color + Possible options: black, red, blue, green + */ + getRecordColor: function(record) { + return null; + }, + + /** + Observes all relevant properties and re-sends the wrapped record + when a change occurs. + + @private + @method observerRecord + @param {Object} record The record instance + @param {Function} recordUpdated The callback to call when a record is updated. + @return {Function} The function to call to remove all observers. + */ + observeRecord: function(record, recordUpdated) { + return function(){}; + } + }); + }); +define("ember-extension-support/initializers", + [], + function() { + "use strict"; + + }); +define("ember-handlebars-compiler", + ["ember-metal/core","exports"], + function(__dependency1__, __exports__) { + "use strict"; + /* global Handlebars:true */ + + /** + @module ember + @submodule ember-handlebars-compiler + */ + + var Ember = __dependency1__["default"]; + + // ES6Todo: you'll need to import debugger once debugger is es6'd. + if (typeof Ember.assert === 'undefined') { Ember.assert = function(){}; } + if (typeof Ember.FEATURES === 'undefined') { Ember.FEATURES = { isEnabled: function(){} }; } + + var objectCreate = Object.create || function(parent) { + function F() {} + F.prototype = parent; + return new F(); + }; + + // set up for circular references later + var View, Component; + + // ES6Todo: when ember-debug is es6'ed import this. + // var emberAssert = Ember.assert; + var Handlebars = (Ember.imports && Ember.imports.Handlebars) || (this && this.Handlebars); + if (!Handlebars && typeof require === 'function') { + Handlebars = require('handlebars'); + } + + Ember.assert("Ember Handlebars requires Handlebars version 1.0 or 1.1. Include " + + "a SCRIPT tag in the HTML HEAD linking to the Handlebars file " + + "before you link to Ember.", Handlebars); + + Ember.assert("Ember Handlebars requires Handlebars version 1.0 or 1.1, " + + "COMPILER_REVISION expected: 4, got: " + Handlebars.COMPILER_REVISION + + " - Please note: Builds of master may have other COMPILER_REVISION values.", + Handlebars.COMPILER_REVISION === 4); + + /** + Prepares the Handlebars templating library for use inside Ember's view + system. + + The `Ember.Handlebars` object is the standard Handlebars library, extended to + use Ember's `get()` method instead of direct property access, which allows + computed properties to be used inside templates. + + To create an `Ember.Handlebars` template, call `Ember.Handlebars.compile()`. + This will return a function that can be used by `Ember.View` for rendering. + + @class Handlebars + @namespace Ember + */ + var EmberHandlebars = Ember.Handlebars = objectCreate(Handlebars); + + /** + Register a bound helper or custom view helper. + + ## Simple bound helper example + + ```javascript + Ember.Handlebars.helper('capitalize', function(value) { + return value.toUpperCase(); + }); + ``` + + The above bound helper can be used inside of templates as follows: + + ```handlebars + {{capitalize name}} + ``` + + In this case, when the `name` property of the template's context changes, + the rendered value of the helper will update to reflect this change. + + For more examples of bound helpers, see documentation for + `Ember.Handlebars.registerBoundHelper`. + + ## Custom view helper example + + Assuming a view subclass named `App.CalendarView` were defined, a helper + for rendering instances of this view could be registered as follows: + + ```javascript + Ember.Handlebars.helper('calendar', App.CalendarView): + ``` + + The above bound helper can be used inside of templates as follows: + + ```handlebars + {{calendar}} + ``` + + Which is functionally equivalent to: + + ```handlebars + {{view App.CalendarView}} + ``` + + Options in the helper will be passed to the view in exactly the same + manner as with the `view` helper. + + @method helper + @for Ember.Handlebars + @param {String} name + @param {Function|Ember.View} function or view class constructor + @param {String} dependentKeys* + */ + EmberHandlebars.helper = function(name, value) { + if (!View) { View = requireModule('ember-views/views/view')['default']; } // ES6TODO: stupid circular dep + if (!Component) { Component = requireModule('ember-views/views/component')['default']; } // ES6TODO: stupid circular dep + + Ember.assert("You tried to register a component named '" + name + "', but component names must include a '-'", !Component.detect(value) || name.match(/-/)); + + if (View.detect(value)) { + EmberHandlebars.registerHelper(name, EmberHandlebars.makeViewHelper(value)); + } else { + EmberHandlebars.registerBoundHelper.apply(null, arguments); + } + }; + + /** + Returns a helper function that renders the provided ViewClass. + + Used internally by Ember.Handlebars.helper and other methods + involving helper/component registration. + + @private + @method makeViewHelper + @for Ember.Handlebars + @param {Function} ViewClass view class constructor + @since 1.2.0 + */ + EmberHandlebars.makeViewHelper = function(ViewClass) { + return function(options) { + Ember.assert("You can only pass attributes (such as name=value) not bare values to a helper for a View found in '" + ViewClass.toString() + "'", arguments.length < 2); + return EmberHandlebars.helpers.view.call(this, ViewClass, options); + }; + }; + + /** + @class helpers + @namespace Ember.Handlebars + */ + EmberHandlebars.helpers = objectCreate(Handlebars.helpers); + + /** + Override the the opcode compiler and JavaScript compiler for Handlebars. + + @class Compiler + @namespace Ember.Handlebars + @private + @constructor + */ + EmberHandlebars.Compiler = function() {}; + + // Handlebars.Compiler doesn't exist in runtime-only + if (Handlebars.Compiler) { + EmberHandlebars.Compiler.prototype = objectCreate(Handlebars.Compiler.prototype); + } + + EmberHandlebars.Compiler.prototype.compiler = EmberHandlebars.Compiler; + + /** + @class JavaScriptCompiler + @namespace Ember.Handlebars + @private + @constructor + */ + EmberHandlebars.JavaScriptCompiler = function() {}; + + // Handlebars.JavaScriptCompiler doesn't exist in runtime-only + if (Handlebars.JavaScriptCompiler) { + EmberHandlebars.JavaScriptCompiler.prototype = objectCreate(Handlebars.JavaScriptCompiler.prototype); + EmberHandlebars.JavaScriptCompiler.prototype.compiler = EmberHandlebars.JavaScriptCompiler; + } + + + EmberHandlebars.JavaScriptCompiler.prototype.namespace = "Ember.Handlebars"; + + EmberHandlebars.JavaScriptCompiler.prototype.initializeBuffer = function() { + return "''"; + }; + + /** + Override the default buffer for Ember Handlebars. By default, Handlebars + creates an empty String at the beginning of each invocation and appends to + it. Ember's Handlebars overrides this to append to a single shared buffer. + + @private + @method appendToBuffer + @param string {String} + */ + EmberHandlebars.JavaScriptCompiler.prototype.appendToBuffer = function(string) { + return "data.buffer.push("+string+");"; + }; + + // Hacks ahead: + // Handlebars presently has a bug where the `blockHelperMissing` hook + // doesn't get passed the name of the missing helper name, but rather + // gets passed the value of that missing helper evaluated on the current + // context, which is most likely `undefined` and totally useless. + // + // So we alter the compiled template function to pass the name of the helper + // instead, as expected. + // + // This can go away once the following is closed: + // https://github.com/wycats/handlebars.js/issues/634 + + var DOT_LOOKUP_REGEX = /helpers\.(.*?)\)/, + BRACKET_STRING_LOOKUP_REGEX = /helpers\['(.*?)'/, + INVOCATION_SPLITTING_REGEX = /(.*blockHelperMissing\.call\(.*)(stack[0-9]+)(,.*)/; + + EmberHandlebars.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation = function(source) { + var helperInvocation = source[source.length - 1], + helperName = (DOT_LOOKUP_REGEX.exec(helperInvocation) || BRACKET_STRING_LOOKUP_REGEX.exec(helperInvocation))[1], + matches = INVOCATION_SPLITTING_REGEX.exec(helperInvocation); + + source[source.length - 1] = matches[1] + "'" + helperName + "'" + matches[3]; + }; + + var stringifyBlockHelperMissing = EmberHandlebars.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation; + + var originalBlockValue = EmberHandlebars.JavaScriptCompiler.prototype.blockValue; + EmberHandlebars.JavaScriptCompiler.prototype.blockValue = function() { + originalBlockValue.apply(this, arguments); + stringifyBlockHelperMissing(this.source); + }; + + var originalAmbiguousBlockValue = EmberHandlebars.JavaScriptCompiler.prototype.ambiguousBlockValue; + EmberHandlebars.JavaScriptCompiler.prototype.ambiguousBlockValue = function() { + originalAmbiguousBlockValue.apply(this, arguments); + stringifyBlockHelperMissing(this.source); + }; + + /** + Rewrite simple mustaches from `{{foo}}` to `{{bind "foo"}}`. This means that + all simple mustaches in Ember's Handlebars will also set up an observer to + keep the DOM up to date when the underlying property changes. + + @private + @method mustache + @for Ember.Handlebars.Compiler + @param mustache + */ + EmberHandlebars.Compiler.prototype.mustache = function(mustache) { + if (!(mustache.params.length || mustache.hash)) { + var id = new Handlebars.AST.IdNode([{ part: '_triageMustache' }]); + + // Update the mustache node to include a hash value indicating whether the original node + // was escaped. This will allow us to properly escape values when the underlying value + // changes and we need to re-render the value. + if (!mustache.escaped) { + mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]); + mustache.hash.pairs.push(["unescaped", new Handlebars.AST.StringNode("true")]); + } + mustache = new Handlebars.AST.MustacheNode([id].concat([mustache.id]), mustache.hash, !mustache.escaped); + } + + return Handlebars.Compiler.prototype.mustache.call(this, mustache); + }; + + /** + Used for precompilation of Ember Handlebars templates. This will not be used + during normal app execution. + + @method precompile + @for Ember.Handlebars + @static + @param {String} string The template to precompile + @param {Boolean} asObject optional parameter, defaulting to true, of whether or not the + compiled template should be returned as an Object or a String + */ + EmberHandlebars.precompile = function(string, asObject) { + var ast = Handlebars.parse(string); + + var options = { + knownHelpers: { + action: true, + unbound: true, + 'bind-attr': true, + template: true, + view: true, + _triageMustache: true + }, + data: true, + stringParams: true + }; + + asObject = asObject === undefined ? true : asObject; + + var environment = new EmberHandlebars.Compiler().compile(ast, options); + return new EmberHandlebars.JavaScriptCompiler().compile(environment, options, undefined, asObject); + }; + + // We don't support this for Handlebars runtime-only + if (Handlebars.compile) { + /** + The entry point for Ember Handlebars. This replaces the default + `Handlebars.compile` and turns on template-local data and String + parameters. + + @method compile + @for Ember.Handlebars + @static + @param {String} string The template to compile + @return {Function} + */ + EmberHandlebars.compile = function(string) { + var ast = Handlebars.parse(string); + var options = { data: true, stringParams: true }; + var environment = new EmberHandlebars.Compiler().compile(ast, options); + var templateSpec = new EmberHandlebars.JavaScriptCompiler().compile(environment, options, undefined, true); + + var template = EmberHandlebars.template(templateSpec); + template.isMethod = false; //Make sure we don't wrap templates with ._super + + return template; + }; + } + + __exports__["default"] = EmberHandlebars; + }); +define("ember-handlebars", + ["ember-handlebars-compiler","ember-metal/core","ember-runtime/system/lazy_load","ember-handlebars/loader","ember-handlebars/ext","ember-handlebars/string","ember-handlebars/helpers/shared","ember-handlebars/helpers/binding","ember-handlebars/helpers/collection","ember-handlebars/helpers/view","ember-handlebars/helpers/unbound","ember-handlebars/helpers/debug","ember-handlebars/helpers/each","ember-handlebars/helpers/template","ember-handlebars/helpers/partial","ember-handlebars/helpers/yield","ember-handlebars/helpers/loc","ember-handlebars/controls/checkbox","ember-handlebars/controls/select","ember-handlebars/controls/text_area","ember-handlebars/controls/text_field","ember-handlebars/controls/text_support","ember-handlebars/controls","ember-handlebars/component_lookup","ember-handlebars/views/handlebars_bound_view","ember-handlebars/views/metamorph_view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __dependency18__, __dependency19__, __dependency20__, __dependency21__, __dependency22__, __dependency23__, __dependency24__, __dependency25__, __dependency26__, __exports__) { + "use strict"; + var EmberHandlebars = __dependency1__["default"]; + var Ember = __dependency2__["default"]; + // to add to globals + + var runLoadHooks = __dependency3__.runLoadHooks; + var bootstrap = __dependency4__["default"]; + + var normalizePath = __dependency5__.normalizePath; + var template = __dependency5__.template; + var makeBoundHelper = __dependency5__.makeBoundHelper; + var registerBoundHelper = __dependency5__.registerBoundHelper; + var resolveHash = __dependency5__.resolveHash; + var resolveParams = __dependency5__.resolveParams; + var getEscaped = __dependency5__.getEscaped; + var handlebarsGet = __dependency5__.handlebarsGet; + var evaluateUnboundHelper = __dependency5__.evaluateUnboundHelper; + var helperMissingHelper = __dependency5__.helperMissingHelper; + var blockHelperMissingHelper = __dependency5__.blockHelperMissingHelper; + + + // side effect of extending StringUtils of htmlSafe + + var resolvePaths = __dependency7__["default"]; + var bind = __dependency8__.bind; + var _triageMustacheHelper = __dependency8__._triageMustacheHelper; + var resolveHelper = __dependency8__.resolveHelper; + var bindHelper = __dependency8__.bindHelper; + var boundIfHelper = __dependency8__.boundIfHelper; + var unboundIfHelper = __dependency8__.unboundIfHelper; + var withHelper = __dependency8__.withHelper; + var ifHelper = __dependency8__.ifHelper; + var unlessHelper = __dependency8__.unlessHelper; + var bindAttrHelper = __dependency8__.bindAttrHelper; + var bindAttrHelperDeprecated = __dependency8__.bindAttrHelperDeprecated; + var bindClasses = __dependency8__.bindClasses; + + var collectionHelper = __dependency9__["default"]; + var ViewHelper = __dependency10__.ViewHelper; + var viewHelper = __dependency10__.viewHelper; + var unboundHelper = __dependency11__["default"]; + var logHelper = __dependency12__.logHelper; + var debuggerHelper = __dependency12__.debuggerHelper; + var EachView = __dependency13__.EachView; + var GroupedEach = __dependency13__.GroupedEach; + var eachHelper = __dependency13__.eachHelper; + var templateHelper = __dependency14__["default"]; + var partialHelper = __dependency15__["default"]; + var yieldHelper = __dependency16__["default"]; + var locHelper = __dependency17__["default"]; + + + var Checkbox = __dependency18__["default"]; + var Select = __dependency19__.Select; + var SelectOption = __dependency19__.SelectOption; + var SelectOptgroup = __dependency19__.SelectOptgroup; + var TextArea = __dependency20__["default"]; + var TextField = __dependency21__["default"]; + var TextSupport = __dependency22__["default"]; + var inputHelper = __dependency23__.inputHelper; + var textareaHelper = __dependency23__.textareaHelper; + + + var ComponentLookup = __dependency24__["default"]; + var _HandlebarsBoundView = __dependency25__._HandlebarsBoundView; + var SimpleHandlebarsView = __dependency25__.SimpleHandlebarsView; + var _wrapMap = __dependency26__._wrapMap; + var _SimpleMetamorphView = __dependency26__._SimpleMetamorphView; + var _MetamorphView = __dependency26__._MetamorphView; + var _Metamorph = __dependency26__._Metamorph; + + + /** + Ember Handlebars + + @module ember + @submodule ember-handlebars + @requires ember-views + */ + + // Ember.Handlebars.Globals + EmberHandlebars.bootstrap = bootstrap; + EmberHandlebars.template = template; + EmberHandlebars.makeBoundHelper = makeBoundHelper; + EmberHandlebars.registerBoundHelper = registerBoundHelper; + EmberHandlebars.resolveHash = resolveHash; + EmberHandlebars.resolveParams = resolveParams; + EmberHandlebars.resolveHelper = resolveHelper; + EmberHandlebars.get = handlebarsGet; + EmberHandlebars.getEscaped = getEscaped; + EmberHandlebars.evaluateUnboundHelper = evaluateUnboundHelper; + EmberHandlebars.bind = bind; + EmberHandlebars.bindClasses = bindClasses; + EmberHandlebars.EachView = EachView; + EmberHandlebars.GroupedEach = GroupedEach; + EmberHandlebars.resolvePaths = resolvePaths; + EmberHandlebars.ViewHelper = ViewHelper; + EmberHandlebars.normalizePath = normalizePath; + + + // Ember Globals + Ember.Handlebars = EmberHandlebars; + Ember.ComponentLookup = ComponentLookup; + Ember._SimpleHandlebarsView = SimpleHandlebarsView; + Ember._HandlebarsBoundView = _HandlebarsBoundView; + Ember._SimpleMetamorphView = _SimpleMetamorphView; + Ember._MetamorphView = _MetamorphView; + Ember._Metamorph = _Metamorph; + Ember._metamorphWrapMap = _wrapMap; + Ember.TextSupport = TextSupport; + Ember.Checkbox = Checkbox; + Ember.Select = Select; + Ember.SelectOption = SelectOption; + Ember.SelectOptgroup = SelectOptgroup; + Ember.TextArea = TextArea; + Ember.TextField = TextField; + Ember.TextSupport = TextSupport; + + // register helpers + EmberHandlebars.registerHelper('helperMissing', helperMissingHelper); + EmberHandlebars.registerHelper('blockHelperMissing', blockHelperMissingHelper); + EmberHandlebars.registerHelper('bind', bindHelper); + EmberHandlebars.registerHelper('boundIf', boundIfHelper); + EmberHandlebars.registerHelper('_triageMustache', _triageMustacheHelper); + EmberHandlebars.registerHelper('unboundIf', unboundIfHelper); + EmberHandlebars.registerHelper('with', withHelper); + EmberHandlebars.registerHelper('if', ifHelper); + EmberHandlebars.registerHelper('unless', unlessHelper); + EmberHandlebars.registerHelper('bind-attr', bindAttrHelper); + EmberHandlebars.registerHelper('bindAttr', bindAttrHelperDeprecated); + EmberHandlebars.registerHelper('collection', collectionHelper); + EmberHandlebars.registerHelper("log", logHelper); + EmberHandlebars.registerHelper("debugger", debuggerHelper); + EmberHandlebars.registerHelper("each", eachHelper); + EmberHandlebars.registerHelper("loc", locHelper); + EmberHandlebars.registerHelper("partial", partialHelper); + EmberHandlebars.registerHelper("template", templateHelper); + EmberHandlebars.registerHelper("yield", yieldHelper); + EmberHandlebars.registerHelper("view", viewHelper); + EmberHandlebars.registerHelper("unbound", unboundHelper); + EmberHandlebars.registerHelper("input", inputHelper); + EmberHandlebars.registerHelper("textarea", textareaHelper); + + // run load hooks + runLoadHooks('Ember.Handlebars', EmberHandlebars); + + __exports__["default"] = EmberHandlebars; + }); +define("ember-handlebars/component_lookup", + ["ember-runtime/system/object","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var EmberObject = __dependency1__["default"]; + + var ComponentLookup = EmberObject.extend({ + lookupFactory: function(name, container) { + + container = container || this.container; + + var fullName = 'component:' + name, + templateFullName = 'template:components/' + name, + templateRegistered = container && container.has(templateFullName); + + if (templateRegistered) { + container.injection(fullName, 'layout', templateFullName); + } + + var Component = container.lookupFactory(fullName); + + // Only treat as a component if either the component + // or a template has been registered. + if (templateRegistered || Component) { + if (!Component) { + container.register(fullName, Ember.Component); + Component = container.lookupFactory(fullName); + } + return Component; + } + } + }); + + __exports__["default"] = ComponentLookup; + }); +define("ember-handlebars/controls", + ["ember-handlebars/controls/checkbox","ember-handlebars/controls/text_field","ember-handlebars/controls/text_area","ember-metal/core","ember-handlebars-compiler","ember-handlebars/ext","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + var Checkbox = __dependency1__["default"]; + var TextField = __dependency2__["default"]; + var TextArea = __dependency3__["default"]; + + var Ember = __dependency4__["default"]; + // Ember.assert + // var emberAssert = Ember.assert; + + var EmberHandlebars = __dependency5__["default"]; + var handlebarsGet = __dependency6__.handlebarsGet; + var helpers = EmberHandlebars.helpers; + /** + @module ember + @submodule ember-handlebars-compiler + */ + + function _resolveOption(context, options, key) { + if (options.hashTypes[key] === "ID") { + return handlebarsGet(context, options.hash[key], options); + } else { + return options.hash[key]; + } + } + + /** + + The `{{input}}` helper inserts an HTML `` tag into the template, + with a `type` value of either `text` or `checkbox`. If no `type` is provided, + `text` will be the default value applied. The attributes of `{{input}}` + match those of the native HTML tag as closely as possible for these two types. + + ## Use as text field + An `{{input}}` with no `type` or a `type` of `text` will render an HTML text input. + The following HTML attributes can be set via the helper: + +
+ + + + + + + + + + +
`readonly``required``autofocus`
`value``placeholder``disabled`
`size``tabindex``maxlength`
`name``min``max`
`pattern``accept``autocomplete`
`autosave``formaction``formenctype`
`formmethod``formnovalidate``formtarget`
`height``inputmode``multiple`
`step``width``form`
`selectionDirection``spellcheck` 
+ + + When set to a quoted string, these values will be directly applied to the HTML + element. When left unquoted, these values will be bound to a property on the + template's current rendering context (most typically a controller instance). + + ## Unbound: + + ```handlebars + {{input value="http://www.facebook.com"}} + ``` + + + ```html + + ``` + + ## Bound: + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + firstName: "Stanley", + entryNotAllowed: true + }); + ``` + + + ```handlebars + {{input type="text" value=firstName disabled=entryNotAllowed size="50"}} + ``` + + + ```html + + ``` + + ## Actions + + The helper can send multiple actions based on user events. + + The action property defines the action which is send when + the user presses the return key. + + ```handlebars + {{input action="submit"}} + ``` + + The helper allows some user events to send actions. + + * `enter` + * `insert-newline` + * `escape-press` + * `focus-in` + * `focus-out` + * `key-press` + + For example, if you desire an action to be sent when the input is blurred, + you only need to setup the action name to the event name property. + + ```handlebars + {{input focus-in="alertMessage"}} + ``` + + See more about [Text Support Actions](/api/classes/Ember.TextField.html) + + ## Extension + + Internally, `{{input type="text"}}` creates an instance of `Ember.TextField`, passing + arguments from the helper to `Ember.TextField`'s `create` method. You can extend the + capabilities of text inputs in your applications by reopening this class. For example, + if you are building a Bootstrap project where `data-*` attributes are used, you + can add one to the `TextField`'s `attributeBindings` property: + + + ```javascript + Ember.TextField.reopen({ + attributeBindings: ['data-error'] + }); + ``` + + Keep in mind when writing `Ember.TextField` subclasses that `Ember.TextField` + itself extends `Ember.Component`, meaning that it does NOT inherit + the `controller` of the parent view. + + See more about [Ember components](/api/classes/Ember.Component.html) + + + ## Use as checkbox + + An `{{input}}` with a `type` of `checkbox` will render an HTML checkbox input. + The following HTML attributes can be set via the helper: + + * `checked` + * `disabled` + * `tabindex` + * `indeterminate` + * `name` + * `autofocus` + * `form` + + + When set to a quoted string, these values will be directly applied to the HTML + element. When left unquoted, these values will be bound to a property on the + template's current rendering context (most typically a controller instance). + + ## Unbound: + + ```handlebars + {{input type="checkbox" name="isAdmin"}} + ``` + + ```html + + ``` + + ## Bound: + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + isAdmin: true + }); + ``` + + + ```handlebars + {{input type="checkbox" checked=isAdmin }} + ``` + + + ```html + + ``` + + ## Extension + + Internally, `{{input type="checkbox"}}` creates an instance of `Ember.Checkbox`, passing + arguments from the helper to `Ember.Checkbox`'s `create` method. You can extend the + capablilties of checkbox inputs in your applications by reopening this class. For example, + if you wanted to add a css class to all checkboxes in your application: + + + ```javascript + Ember.Checkbox.reopen({ + classNames: ['my-app-checkbox'] + }); + ``` + + + @method input + @for Ember.Handlebars.helpers + @param {Hash} options + */ + function inputHelper(options) { + Ember.assert('You can only pass attributes to the `input` helper, not arguments', arguments.length < 2); + + var hash = options.hash, + types = options.hashTypes, + inputType = _resolveOption(this, options, 'type'), + onEvent = hash.on; + + delete hash.type; + delete hash.on; + + if (inputType === 'checkbox') { + Ember.assert("{{input type='checkbox'}} does not support setting `value=someBooleanValue`; you must use `checked=someBooleanValue` instead.", options.hashTypes.value !== 'ID'); + return helpers.view.call(this, Checkbox, options); + } else { + if (inputType) { hash.type = inputType; } + hash.onEvent = onEvent || 'enter'; + return helpers.view.call(this, TextField, options); + } + } + + __exports__.inputHelper = inputHelper;/** + `{{textarea}}` inserts a new instance of ` + ``` + + Bound: + + In the following example, the `writtenWords` property on `App.ApplicationController` + will be updated live as the user types 'Lots of text that IS bound' into + the text area of their browser's window. + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + writtenWords: "Lots of text that IS bound" + }); + ``` + + ```handlebars + {{textarea value=writtenWords}} + ``` + + Would result in the following HTML: + + ```html + + ``` + + If you wanted a one way binding between the text area and a div tag + somewhere else on your screen, you could use `Ember.computed.oneWay`: + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + writtenWords: "Lots of text that IS bound", + outputWrittenWords: Ember.computed.oneWay("writtenWords") + }); + ``` + + ```handlebars + {{textarea value=writtenWords}} + +
+ {{outputWrittenWords}} +
+ ``` + + Would result in the following HTML: + + ```html + + + <-- the following div will be updated in real time as you type --> + +
+ Lots of text that IS bound +
+ ``` + + Finally, this example really shows the power and ease of Ember when two + properties are bound to eachother via `Ember.computed.alias`. Type into + either text area box and they'll both stay in sync. Note that + `Ember.computed.alias` costs more in terms of performance, so only use it when + your really binding in both directions: + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + writtenWords: "Lots of text that IS bound", + twoWayWrittenWords: Ember.computed.alias("writtenWords") + }); + ``` + + ```handlebars + {{textarea value=writtenWords}} + {{textarea value=twoWayWrittenWords}} + ``` + + ```html + + + <-- both updated in real time --> + + + ``` + + ## Actions + + The helper can send multiple actions based on user events. + + The action property defines the action which is send when + the user presses the return key. + + ```handlebars + {{input action="submit"}} + ``` + + The helper allows some user events to send actions. + + * `enter` + * `insert-newline` + * `escape-press` + * `focus-in` + * `focus-out` + * `key-press` + + For example, if you desire an action to be sent when the input is blurred, + you only need to setup the action name to the event name property. + + ```handlebars + {{textarea focus-in="alertMessage"}} + ``` + + See more about [Text Support Actions](/api/classes/Ember.TextArea.html) + + ## Extension + + Internally, `{{textarea}}` creates an instance of `Ember.TextArea`, passing + arguments from the helper to `Ember.TextArea`'s `create` method. You can + extend the capabilities of text areas in your application by reopening this + class. For example, if you are building a Bootstrap project where `data-*` + attributes are used, you can globally add support for a `data-*` attribute + on all `{{textarea}}`s' in your app by reopening `Ember.TextArea` or + `Ember.TextSupport` and adding it to the `attributeBindings` concatenated + property: + + ```javascript + Ember.TextArea.reopen({ + attributeBindings: ['data-error'] + }); + ``` + + Keep in mind when writing `Ember.TextArea` subclasses that `Ember.TextArea` + itself extends `Ember.Component`, meaning that it does NOT inherit + the `controller` of the parent view. + + See more about [Ember components](/api/classes/Ember.Component.html) + + @method textarea + @for Ember.Handlebars.helpers + @param {Hash} options + */ + function textareaHelper(options) { + Ember.assert('You can only pass attributes to the `textarea` helper, not arguments', arguments.length < 2); + + var hash = options.hash, + types = options.hashTypes; + + return helpers.view.call(this, TextArea, options); + } + + __exports__.textareaHelper = textareaHelper; + }); +define("ember-handlebars/controls/checkbox", + ["ember-metal/property_get","ember-metal/property_set","ember-views/views/view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var set = __dependency2__.set; + var View = __dependency3__["default"]; + + /** + @module ember + @submodule ember-handlebars + */ + + /** + The internal class used to create text inputs when the `{{input}}` + helper is used with `type` of `checkbox`. + + See [handlebars.helpers.input](/api/classes/Ember.Handlebars.helpers.html#method_input) for usage details. + + ## Direct manipulation of `checked` + + The `checked` attribute of an `Ember.Checkbox` object should always be set + through the Ember object or by interacting with its rendered element + representation via the mouse, keyboard, or touch. Updating the value of the + checkbox via jQuery will result in the checked value of the object and its + element losing synchronization. + + ## Layout and LayoutName properties + + Because HTML `input` elements are self closing `layout` and `layoutName` + properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s + layout section for more information. + + @class Checkbox + @namespace Ember + @extends Ember.View + */ + __exports__["default"] = View.extend({ + instrumentDisplay: '{{input type="checkbox"}}', + + classNames: ['ember-checkbox'], + + tagName: 'input', + + attributeBindings: [ + 'type', + 'checked', + 'indeterminate', + 'disabled', + 'tabindex', + 'name', + 'autofocus', + 'required', + 'form' + ], + + type: 'checkbox', + checked: false, + disabled: false, + indeterminate: false, + + init: function() { + this._super(); + this.on('change', this, this._updateElementValue); + }, + + didInsertElement: function() { + this._super(); + get(this, 'element').indeterminate = !!get(this, 'indeterminate'); + }, + + _updateElementValue: function() { + set(this, 'checked', this.$().prop('checked')); + } + }); + }); +define("ember-handlebars/controls/select", + ["ember-handlebars-compiler","ember-metal/enumerable_utils","ember-metal/property_get","ember-metal/property_set","ember-views/views/view","ember-views/views/collection_view","ember-metal/utils","ember-metal/is_none","ember-metal/computed","ember-runtime/system/native_array","ember-metal/mixin","ember-metal/properties","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var EmberHandlebars = __dependency1__["default"]; + + var forEach = __dependency2__.forEach; + var indexOf = __dependency2__.indexOf; + var indexesOf = __dependency2__.indexesOf; + var replace = __dependency2__.replace; + + var get = __dependency3__.get; + var set = __dependency4__.set; + var View = __dependency5__["default"]; + var CollectionView = __dependency6__["default"]; + var isArray = __dependency7__.isArray; + var isNone = __dependency8__["default"]; + var computed = __dependency9__.computed; + var emberA = __dependency10__.A; + var observer = __dependency11__.observer; + var defineProperty = __dependency12__.defineProperty; + + var precompileTemplate = EmberHandlebars.compile; + + var SelectOption = View.extend({ + instrumentDisplay: 'Ember.SelectOption', + + tagName: 'option', + attributeBindings: ['value', 'selected'], + + defaultTemplate: function(context, options) { + options = { data: options.data, hash: {} }; + EmberHandlebars.helpers.bind.call(context, "view.label", options); + }, + + init: function() { + this.labelPathDidChange(); + this.valuePathDidChange(); + + this._super(); + }, + + selected: computed(function() { + var content = get(this, 'content'), + selection = get(this, 'parentView.selection'); + if (get(this, 'parentView.multiple')) { + return selection && indexOf(selection, content.valueOf()) > -1; + } else { + // Primitives get passed through bindings as objects... since + // `new Number(4) !== 4`, we use `==` below + return content == selection; // jshint ignore:line + } + }).property('content', 'parentView.selection'), + + labelPathDidChange: observer('parentView.optionLabelPath', function() { + var labelPath = get(this, 'parentView.optionLabelPath'); + + if (!labelPath) { return; } + + defineProperty(this, 'label', computed(function() { + return get(this, labelPath); + }).property(labelPath)); + }), + + valuePathDidChange: observer('parentView.optionValuePath', function() { + var valuePath = get(this, 'parentView.optionValuePath'); + + if (!valuePath) { return; } + + defineProperty(this, 'value', computed(function() { + return get(this, valuePath); + }).property(valuePath)); + }) + }); + + var SelectOptgroup = CollectionView.extend({ + instrumentDisplay: 'Ember.SelectOptgroup', + + tagName: 'optgroup', + attributeBindings: ['label'], + + selectionBinding: 'parentView.selection', + multipleBinding: 'parentView.multiple', + optionLabelPathBinding: 'parentView.optionLabelPath', + optionValuePathBinding: 'parentView.optionValuePath', + + itemViewClassBinding: 'parentView.optionView' + }); + + /** + The `Ember.Select` view class renders a + [select](https://developer.mozilla.org/en/HTML/Element/select) HTML element, + allowing the user to choose from a list of options. + + The text and `value` property of each ` + + + ``` + + The `value` attribute of the selected `"); + return buffer; + } + + function program3(depth0,data) { + + var stack1; + stack1 = helpers.each.call(depth0, "view.groupedContent", {hash:{},hashTypes:{},hashContexts:{},inverse:self.noop,fn:self.program(4, program4, data),contexts:[depth0],types:["ID"],data:data}); + if(stack1 || stack1 === 0) { data.buffer.push(stack1); } + else { data.buffer.push(''); } + } + function program4(depth0,data) { + + + data.buffer.push(escapeExpression(helpers.view.call(depth0, "view.groupView", {hash:{ + 'content': ("content"), + 'label': ("label") + },hashTypes:{'content': "ID",'label': "ID"},hashContexts:{'content': depth0,'label': depth0},contexts:[depth0],types:["ID"],data:data}))); + } + + function program6(depth0,data) { + + var stack1; + stack1 = helpers.each.call(depth0, "view.content", {hash:{},hashTypes:{},hashContexts:{},inverse:self.noop,fn:self.program(7, program7, data),contexts:[depth0],types:["ID"],data:data}); + if(stack1 || stack1 === 0) { data.buffer.push(stack1); } + else { data.buffer.push(''); } + } + function program7(depth0,data) { + + + data.buffer.push(escapeExpression(helpers.view.call(depth0, "view.optionView", {hash:{ + 'content': ("") + },hashTypes:{'content': "ID"},hashContexts:{'content': depth0},contexts:[depth0],types:["ID"],data:data}))); + } + + stack1 = helpers['if'].call(depth0, "view.prompt", {hash:{},hashTypes:{},hashContexts:{},inverse:self.noop,fn:self.program(1, program1, data),contexts:[depth0],types:["ID"],data:data}); + if(stack1 || stack1 === 0) { data.buffer.push(stack1); } + stack1 = helpers['if'].call(depth0, "view.optionGroupPath", {hash:{},hashTypes:{},hashContexts:{},inverse:self.program(6, program6, data),fn:self.program(3, program3, data),contexts:[depth0],types:["ID"],data:data}); + if(stack1 || stack1 === 0) { data.buffer.push(stack1); } + return buffer; + + }), + attributeBindings: ['multiple', 'disabled', 'tabindex', 'name', 'required', 'autofocus', + 'form', 'size'], + + /** + The `multiple` attribute of the select element. Indicates whether multiple + options can be selected. + + @property multiple + @type Boolean + @default false + */ + multiple: false, + + /** + The `disabled` attribute of the select element. Indicates whether + the element is disabled from interactions. + + @property disabled + @type Boolean + @default false + */ + disabled: false, + + /** + The `required` attribute of the select element. Indicates whether + a selected option is required for form validation. + + @property required + @type Boolean + @default false + @since 1.5.0 + */ + required: false, + + /** + The list of options. + + If `optionLabelPath` and `optionValuePath` are not overridden, this should + be a list of strings, which will serve simultaneously as labels and values. + + Otherwise, this should be a list of objects. For instance: + + ```javascript + Ember.Select.create({ + content: Ember.A([ + { id: 1, firstName: 'Yehuda' }, + { id: 2, firstName: 'Tom' } + ]), + optionLabelPath: 'content.firstName', + optionValuePath: 'content.id' + }); + ``` + + @property content + @type Array + @default null + */ + content: null, + + /** + When `multiple` is `false`, the element of `content` that is currently + selected, if any. + + When `multiple` is `true`, an array of such elements. + + @property selection + @type Object or Array + @default null + */ + selection: null, + + /** + In single selection mode (when `multiple` is `false`), value can be used to + get the current selection's value or set the selection by it's value. + + It is not currently supported in multiple selection mode. + + @property value + @type String + @default null + */ + value: computed(function(key, value) { + if (arguments.length === 2) { return value; } + var valuePath = get(this, 'optionValuePath').replace(/^content\.?/, ''); + return valuePath ? get(this, 'selection.' + valuePath) : get(this, 'selection'); + }).property('selection'), + + /** + If given, a top-most dummy option will be rendered to serve as a user + prompt. + + @property prompt + @type String + @default null + */ + prompt: null, + + /** + The path of the option labels. See [content](/api/classes/Ember.Select.html#property_content). + + @property optionLabelPath + @type String + @default 'content' + */ + optionLabelPath: 'content', + + /** + The path of the option values. See [content](/api/classes/Ember.Select.html#property_content). + + @property optionValuePath + @type String + @default 'content' + */ + optionValuePath: 'content', + + /** + The path of the option group. + When this property is used, `content` should be sorted by `optionGroupPath`. + + @property optionGroupPath + @type String + @default null + */ + optionGroupPath: null, + + /** + The view class for optgroup. + + @property groupView + @type Ember.View + @default Ember.SelectOptgroup + */ + groupView: SelectOptgroup, + + groupedContent: computed(function() { + var groupPath = get(this, 'optionGroupPath'); + var groupedContent = emberA(); + var content = get(this, 'content') || []; + + forEach(content, function(item) { + var label = get(item, groupPath); + + if (get(groupedContent, 'lastObject.label') !== label) { + groupedContent.pushObject({ + label: label, + content: emberA() + }); + } + + get(groupedContent, 'lastObject.content').push(item); + }); + + return groupedContent; + }).property('optionGroupPath', 'content.@each'), + + /** + The view class for option. + + @property optionView + @type Ember.View + @default Ember.SelectOption + */ + optionView: SelectOption, + + _change: function() { + if (get(this, 'multiple')) { + this._changeMultiple(); + } else { + this._changeSingle(); + } + }, + + selectionDidChange: observer('selection.@each', function() { + var selection = get(this, 'selection'); + if (get(this, 'multiple')) { + if (!isArray(selection)) { + set(this, 'selection', emberA([selection])); + return; + } + this._selectionDidChangeMultiple(); + } else { + this._selectionDidChangeSingle(); + } + }), + + valueDidChange: observer('value', function() { + var content = get(this, 'content'), + value = get(this, 'value'), + valuePath = get(this, 'optionValuePath').replace(/^content\.?/, ''), + selectedValue = (valuePath ? get(this, 'selection.' + valuePath) : get(this, 'selection')), + selection; + + if (value !== selectedValue) { + selection = content ? content.find(function(obj) { + return value === (valuePath ? get(obj, valuePath) : obj); + }) : null; + + this.set('selection', selection); + } + }), + + + _triggerChange: function() { + var selection = get(this, 'selection'); + var value = get(this, 'value'); + + if (!isNone(selection)) { this.selectionDidChange(); } + if (!isNone(value)) { this.valueDidChange(); } + + this._change(); + }, + + _changeSingle: function() { + var selectedIndex = this.$()[0].selectedIndex, + content = get(this, 'content'), + prompt = get(this, 'prompt'); + + if (!content || !get(content, 'length')) { return; } + if (prompt && selectedIndex === 0) { set(this, 'selection', null); return; } + + if (prompt) { selectedIndex -= 1; } + set(this, 'selection', content.objectAt(selectedIndex)); + }, + + + _changeMultiple: function() { + var options = this.$('option:selected'), + prompt = get(this, 'prompt'), + offset = prompt ? 1 : 0, + content = get(this, 'content'), + selection = get(this, 'selection'); + + if (!content) { return; } + if (options) { + var selectedIndexes = options.map(function() { + return this.index - offset; + }).toArray(); + var newSelection = content.objectsAt(selectedIndexes); + + if (isArray(selection)) { + replace(selection, 0, get(selection, 'length'), newSelection); + } else { + set(this, 'selection', newSelection); + } + } + }, + + _selectionDidChangeSingle: function() { + var el = this.get('element'); + if (!el) { return; } + + var content = get(this, 'content'), + selection = get(this, 'selection'), + selectionIndex = content ? indexOf(content, selection) : -1, + prompt = get(this, 'prompt'); + + if (prompt) { selectionIndex += 1; } + if (el) { el.selectedIndex = selectionIndex; } + }, + + _selectionDidChangeMultiple: function() { + var content = get(this, 'content'), + selection = get(this, 'selection'), + selectedIndexes = content ? indexesOf(content, selection) : [-1], + prompt = get(this, 'prompt'), + offset = prompt ? 1 : 0, + options = this.$('option'), + adjusted; + + if (options) { + options.each(function() { + adjusted = this.index > -1 ? this.index - offset : -1; + this.selected = indexOf(selectedIndexes, adjusted) > -1; + }); + } + }, + + init: function() { + this._super(); + this.on("didInsertElement", this, this._triggerChange); + this.on("change", this, this._change); + } + }); + + __exports__["default"] = Select; + __exports__.Select = Select; + __exports__.SelectOption = SelectOption; + __exports__.SelectOptgroup = SelectOptgroup; + }); +define("ember-handlebars/controls/text_area", + ["ember-metal/property_get","ember-views/views/component","ember-handlebars/controls/text_support","ember-metal/mixin","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + + /** + @module ember + @submodule ember-handlebars + */ + var get = __dependency1__.get; + var Component = __dependency2__["default"]; + var TextSupport = __dependency3__["default"]; + var observer = __dependency4__.observer; + + /** + The internal class used to create textarea element when the `{{textarea}}` + helper is used. + + See [handlebars.helpers.textarea](/api/classes/Ember.Handlebars.helpers.html#method_textarea) for usage details. + + ## Layout and LayoutName properties + + Because HTML `textarea` elements do not contain inner HTML the `layout` and + `layoutName` properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s + layout section for more information. + + @class TextArea + @namespace Ember + @extends Ember.Component + @uses Ember.TextSupport + */ + __exports__["default"] = Component.extend(TextSupport, { + instrumentDisplay: '{{textarea}}', + + classNames: ['ember-text-area'], + + tagName: "textarea", + attributeBindings: ['rows', 'cols', 'name', 'selectionEnd', 'selectionStart', 'wrap'], + rows: null, + cols: null, + + _updateElementValue: observer('value', function() { + // We do this check so cursor position doesn't get affected in IE + var value = get(this, 'value'), + $el = this.$(); + if ($el && value !== $el.val()) { + $el.val(value); + } + }), + + init: function() { + this._super(); + this.on("didInsertElement", this, this._updateElementValue); + } + }); + }); +define("ember-handlebars/controls/text_field", + ["ember-metal/property_get","ember-metal/property_set","ember-views/views/component","ember-handlebars/controls/text_support","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var get = __dependency1__.get; + var set = __dependency2__.set; + var Component = __dependency3__["default"]; + var TextSupport = __dependency4__["default"]; + + /** + + The internal class used to create text inputs when the `{{input}}` + helper is used with `type` of `text`. + + See [Handlebars.helpers.input](/api/classes/Ember.Handlebars.helpers.html#method_input) for usage details. + + ## Layout and LayoutName properties + + Because HTML `input` elements are self closing `layout` and `layoutName` + properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s + layout section for more information. + + @class TextField + @namespace Ember + @extends Ember.Component + @uses Ember.TextSupport + */ + __exports__["default"] = Component.extend(TextSupport, { + instrumentDisplay: '{{input type="text"}}', + + classNames: ['ember-text-field'], + tagName: "input", + attributeBindings: ['type', 'value', 'size', 'pattern', 'name', 'min', 'max', + 'accept', 'autocomplete', 'autosave', 'formaction', + 'formenctype', 'formmethod', 'formnovalidate', 'formtarget', + 'height', 'inputmode', 'list', 'multiple', 'step', + 'width'], + + /** + The `value` attribute of the input element. As the user inputs text, this + property is updated live. + + @property value + @type String + @default "" + */ + value: "", + + /** + The `type` attribute of the input element. + + @property type + @type String + @default "text" + */ + type: "text", + + /** + The `size` of the text field in characters. + + @property size + @type String + @default null + */ + size: null, + + /** + The `pattern` attribute of input element. + + @property pattern + @type String + @default null + */ + pattern: null, + + /** + The `min` attribute of input element used with `type="number"` or `type="range"`. + + @property min + @type String + @default null + @since 1.4.0 + */ + min: null, + + /** + The `max` attribute of input element used with `type="number"` or `type="range"`. + + @property max + @type String + @default null + @since 1.4.0 + */ + max: null + }); + }); +define("ember-handlebars/controls/text_support", + ["ember-metal/property_get","ember-metal/property_set","ember-metal/mixin","ember-runtime/mixins/target_action_support","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var get = __dependency1__.get; + var set = __dependency2__.set; + var Mixin = __dependency3__.Mixin; + var TargetActionSupport = __dependency4__["default"]; + + /** + Shared mixin used by `Ember.TextField` and `Ember.TextArea`. + + @class TextSupport + @namespace Ember + @uses Ember.TargetActionSupport + @extends Ember.Mixin + @private + */ + var TextSupport = Mixin.create(TargetActionSupport, { + value: "", + + attributeBindings: ['placeholder', 'disabled', 'maxlength', 'tabindex', 'readonly', + 'autofocus', 'form', 'selectionDirection', 'spellcheck', 'required', + 'title', 'autocapitalize', 'autocorrect'], + placeholder: null, + disabled: false, + maxlength: null, + + init: function() { + this._super(); + this.on("focusOut", this, this._elementValueDidChange); + this.on("change", this, this._elementValueDidChange); + this.on("paste", this, this._elementValueDidChange); + this.on("cut", this, this._elementValueDidChange); + this.on("input", this, this._elementValueDidChange); + this.on("keyUp", this, this.interpretKeyEvents); + }, + + /** + The action to be sent when the user presses the return key. + + This is similar to the `{{action}}` helper, but is fired when + the user presses the return key when editing a text field, and sends + the value of the field as the context. + + @property action + @type String + @default null + */ + action: null, + + /** + The event that should send the action. + + Options are: + + * `enter`: the user pressed enter + * `keyPress`: the user pressed a key + + @property onEvent + @type String + @default enter + */ + onEvent: 'enter', + + /** + Whether they `keyUp` event that triggers an `action` to be sent continues + propagating to other views. + + By default, when the user presses the return key on their keyboard and + the text field has an `action` set, the action will be sent to the view's + controller and the key event will stop propagating. + + If you would like parent views to receive the `keyUp` event even after an + action has been dispatched, set `bubbles` to true. + + @property bubbles + @type Boolean + @default false + */ + bubbles: false, + + interpretKeyEvents: function(event) { + var map = TextSupport.KEY_EVENTS; + var method = map[event.keyCode]; + + this._elementValueDidChange(); + if (method) { return this[method](event); } + }, + + _elementValueDidChange: function() { + set(this, 'value', this.$().val()); + }, + + /** + Called when the user inserts a new line. + + Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 13. + Uses sendAction to send the `enter` action. + + @method insertNewline + @param {Event} event + */ + insertNewline: function(event) { + sendAction('enter', this, event); + sendAction('insert-newline', this, event); + }, + + /** + Called when the user hits escape. + + Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 27. + Uses sendAction to send the `escape-press` action. + + @method cancel + @param {Event} event + */ + cancel: function(event) { + sendAction('escape-press', this, event); + }, + + /** + Called when the text area is focused. + + Uses sendAction to send the `focus-in` action. + + @method focusIn + @param {Event} event + */ + focusIn: function(event) { + sendAction('focus-in', this, event); + }, + + /** + Called when the text area is blurred. + + Uses sendAction to send the `focus-out` action. + + @method focusOut + @param {Event} event + */ + focusOut: function(event) { + sendAction('focus-out', this, event); + }, + + /** + Called when the user presses a key. Enabled by setting + the `onEvent` property to `keyPress`. + + Uses sendAction to send the `key-press` action. + + @method keyPress + @param {Event} event + */ + keyPress: function(event) { + sendAction('key-press', this, event); + } + + }); + + TextSupport.KEY_EVENTS = { + 13: 'insertNewline', + 27: 'cancel' + }; + + // In principle, this shouldn't be necessary, but the legacy + // sendAction semantics for TextField are different from + // the component semantics so this method normalizes them. + function sendAction(eventName, view, event) { + var action = get(view, eventName), + on = get(view, 'onEvent'), + value = get(view, 'value'); + + // back-compat support for keyPress as an event name even though + // it's also a method name that consumes the event (and therefore + // incompatible with sendAction semantics). + if (on === eventName || (on === 'keyPress' && eventName === 'key-press')) { + view.sendAction('action', value); + } + + view.sendAction(eventName, value); + + if (action || on === eventName) { + if(!get(view, 'bubbles')) { + event.stopPropagation(); + } + } + } + + __exports__["default"] = TextSupport; + }); +define("ember-handlebars/ext", + ["ember-metal/core","ember-runtime/system/string","ember-handlebars-compiler","ember-metal/property_get","ember-metal/binding","ember-metal/error","ember-metal/mixin","ember-metal/is_empty","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.FEATURES, Ember.assert, Ember.Handlebars, Ember.lookup + // var emberAssert = Ember.assert; + + var fmt = __dependency2__.fmt; + + var EmberHandlebars = __dependency3__["default"]; + var helpers = EmberHandlebars.helpers; + + var get = __dependency4__.get; + var isGlobalPath = __dependency5__.isGlobalPath; + var EmberError = __dependency6__["default"]; + var IS_BINDING = __dependency7__.IS_BINDING; + + // late bound via requireModule because of circular dependencies. + var resolveHelper, + SimpleHandlebarsView; + + var isEmpty = __dependency8__["default"]; + + var slice = [].slice, originalTemplate = EmberHandlebars.template; + + /** + If a path starts with a reserved keyword, returns the root + that should be used. + + @private + @method normalizePath + @for Ember + @param root {Object} + @param path {String} + @param data {Hash} + */ + function normalizePath(root, path, data) { + var keywords = (data && data.keywords) || {}, + keyword, isKeyword; + + // Get the first segment of the path. For example, if the + // path is "foo.bar.baz", returns "foo". + keyword = path.split('.', 1)[0]; + + // Test to see if the first path is a keyword that has been + // passed along in the view's data hash. If so, we will treat + // that object as the new root. + if (keywords.hasOwnProperty(keyword)) { + // Look up the value in the template's data hash. + root = keywords[keyword]; + isKeyword = true; + + // Handle cases where the entire path is the reserved + // word. In that case, return the object itself. + if (path === keyword) { + path = ''; + } else { + // Strip the keyword from the path and look up + // the remainder from the newly found root. + path = path.substr(keyword.length+1); + } + } + + return { root: root, path: path, isKeyword: isKeyword }; + } + + + /** + Lookup both on root and on window. If the path starts with + a keyword, the corresponding object will be looked up in the + template's data hash and used to resolve the path. + + @method get + @for Ember.Handlebars + @param {Object} root The object to look up the property on + @param {String} path The path to be lookedup + @param {Object} options The template's option hash + */ + function handlebarsGet(root, path, options) { + var data = options && options.data, + normalizedPath = normalizePath(root, path, data), + value; + + + root = normalizedPath.root; + path = normalizedPath.path; + + value = get(root, path); + + if (value === undefined && root !== Ember.lookup && isGlobalPath(path)) { + value = get(Ember.lookup, path); + } + + + return value; + } + + /** + This method uses `Ember.Handlebars.get` to lookup a value, then ensures + that the value is escaped properly. + + If `unescaped` is a truthy value then the escaping will not be performed. + + @method getEscaped + @for Ember.Handlebars + @param {Object} root The object to look up the property on + @param {String} path The path to be lookedup + @param {Object} options The template's option hash + @since 1.4.0 + */ + function getEscaped(root, path, options) { + var result = handlebarsGet(root, path, options); + + if (result === null || result === undefined) { + result = ""; + } else if (!(result instanceof Handlebars.SafeString)) { + result = String(result); + } + if (!options.hash.unescaped){ + result = Handlebars.Utils.escapeExpression(result); + } + + return result; + } + + __exports__.getEscaped = getEscaped;function resolveParams(context, params, options) { + var resolvedParams = [], types = options.types, param, type; + + for (var i=0, l=params.length; i{{user.name}} + +
+
{{user.role.label}}
+ {{user.role.id}} + +

{{user.role.description}}

+
+ ``` + + `{{with}}` can be our best friend in these cases, + instead of writing `user.role.*` over and over, we use `{{#with user.role}}`. + Now the context within the `{{#with}} .. {{/with}}` block is `user.role` so you can do the following: + + ```handlebars +
{{user.name}}
+ +
+ {{#with user.role}} +
{{label}}
+ {{id}} + +

{{description}}

+ {{/with}} +
+ ``` + + ### `as` operator + + This operator aliases the scope to a new name. It's helpful for semantic clarity and to retain + default scope or to reference from another `{{with}}` block. + + ```handlebars + // posts might not be + {{#with user.posts as blogPosts}} +
+ There are {{blogPosts.length}} blog posts written by {{user.name}}. +
+ + {{#each post in blogPosts}} +
  • {{post.title}}
  • + {{/each}} + {{/with}} + ``` + + Without the `as` operator, it would be impossible to reference `user.name` in the example above. + + NOTE: The alias should not reuse a name from the bound property path. + For example: `{{#with foo.bar as foo}}` is not supported because it attempts to alias using + the first part of the property path, `foo`. Instead, use `{{#with foo.bar as baz}}`. + + ### `controller` option + + Adding `controller='something'` instructs the `{{with}}` helper to create and use an instance of + the specified controller with the new context as its content. + + This is very similar to using an `itemController` option with the `{{each}}` helper. + + ```handlebars + {{#with users.posts controller='userBlogPosts'}} + {{!- The current context is wrapped in our controller instance }} + {{/with}} + ``` + + In the above example, the template provided to the `{{with}}` block is now wrapped in the + `userBlogPost` controller, which provides a very elegant way to decorate the context with custom + functions/properties. + + @method with + @for Ember.Handlebars.helpers + @param {Function} context + @param {Hash} options + @return {String} HTML string + */ + function withHelper(context, options) { + var bindContext, preserveContext, controller, helperName = 'with'; + + if (arguments.length === 4) { + var keywordName, path, rootPath, normalized, contextPath; + + Ember.assert("If you pass more than one argument to the with helper, it must be in the form #with foo as bar", arguments[1] === "as"); + options = arguments[3]; + keywordName = arguments[2]; + path = arguments[0]; + + if (path) { + helperName += ' ' + path + ' as ' + keywordName; + } + + Ember.assert("You must pass a block to the with helper", options.fn && options.fn !== Handlebars.VM.noop); + + var localizedOptions = o_create(options); + localizedOptions.data = o_create(options.data); + localizedOptions.data.keywords = o_create(options.data.keywords || {}); + + if (isGlobalPath(path)) { + contextPath = path; + } else { + normalized = normalizePath(this, path, options.data); + path = normalized.path; + rootPath = normalized.root; + + // This is a workaround for the fact that you cannot bind separate objects + // together. When we implement that functionality, we should use it here. + var contextKey = jQuery.expando + guidFor(rootPath); + localizedOptions.data.keywords[contextKey] = rootPath; + // if the path is '' ("this"), just bind directly to the current context + contextPath = path ? contextKey + '.' + path : contextKey; + } + + localizedOptions.hash.keywordName = keywordName; + localizedOptions.hash.keywordPath = contextPath; + + bindContext = this; + context = contextPath; + options = localizedOptions; + preserveContext = true; + } else { + Ember.assert("You must pass exactly one argument to the with helper", arguments.length === 2); + Ember.assert("You must pass a block to the with helper", options.fn && options.fn !== Handlebars.VM.noop); + + helperName += ' ' + context; + bindContext = options.contexts[0]; + preserveContext = false; + } + + options.helperName = helperName; + options.isWithHelper = true; + + return bind.call(bindContext, context, options, preserveContext, exists); + } + /** + See [boundIf](/api/classes/Ember.Handlebars.helpers.html#method_boundIf) + and [unboundIf](/api/classes/Ember.Handlebars.helpers.html#method_unboundIf) + + @method if + @for Ember.Handlebars.helpers + @param {Function} context + @param {Hash} options + @return {String} HTML string + */ + function ifHelper(context, options) { + Ember.assert("You must pass exactly one argument to the if helper", arguments.length === 2); + Ember.assert("You must pass a block to the if helper", options.fn && options.fn !== Handlebars.VM.noop); + + options.helperName = options.helperName || ('if ' + context); + + if (options.data.isUnbound) { + return helpers.unboundIf.call(options.contexts[0], context, options); + } else { + return helpers.boundIf.call(options.contexts[0], context, options); + } + } + + /** + @method unless + @for Ember.Handlebars.helpers + @param {Function} context + @param {Hash} options + @return {String} HTML string + */ + function unlessHelper(context, options) { + Ember.assert("You must pass exactly one argument to the unless helper", arguments.length === 2); + Ember.assert("You must pass a block to the unless helper", options.fn && options.fn !== Handlebars.VM.noop); + + var fn = options.fn, inverse = options.inverse, helperName = 'unless'; + + if (context) { + helperName += ' ' + context; + } + + options.fn = inverse; + options.inverse = fn; + + options.helperName = options.helperName || helperName; + + if (options.data.isUnbound) { + return helpers.unboundIf.call(options.contexts[0], context, options); + } else { + return helpers.boundIf.call(options.contexts[0], context, options); + } + } + + /** + `bind-attr` allows you to create a binding between DOM element attributes and + Ember objects. For example: + + ```handlebars + imageTitle + ``` + + The above handlebars template will fill the ``'s `src` attribute with + the value of the property referenced with `"imageUrl"` and its `alt` + attribute with the value of the property referenced with `"imageTitle"`. + + If the rendering context of this template is the following object: + + ```javascript + { + imageUrl: 'http://lolcats.info/haz-a-funny', + imageTitle: 'A humorous image of a cat' + } + ``` + + The resulting HTML output will be: + + ```html + A humorous image of a cat + ``` + + `bind-attr` cannot redeclare existing DOM element attributes. The use of `src` + in the following `bind-attr` example will be ignored and the hard coded value + of `src="/failwhale.gif"` will take precedence: + + ```handlebars + imageTitle + ``` + + ### `bind-attr` and the `class` attribute + + `bind-attr` supports a special syntax for handling a number of cases unique + to the `class` DOM element attribute. The `class` attribute combines + multiple discrete values into a single attribute as a space-delimited + list of strings. Each string can be: + + * a string return value of an object's property. + * a boolean return value of an object's property + * a hard-coded value + + A string return value works identically to other uses of `bind-attr`. The + return value of the property will become the value of the attribute. For + example, the following view and template: + + ```javascript + AView = View.extend({ + someProperty: function() { + return "aValue"; + }.property() + }) + ``` + + ```handlebars + + ``` + + A boolean return value will insert a specified class name if the property + returns `true` and remove the class name if the property returns `false`. + + A class name is provided via the syntax + `somePropertyName:class-name-if-true`. + + ```javascript + AView = View.extend({ + someBool: true + }) + ``` + + ```handlebars + + ``` + + Result in the following rendered output: + + ```html + + ``` + + An additional section of the binding can be provided if you want to + replace the existing class instead of removing it when the boolean + value changes: + + ```handlebars + + ``` + + A hard-coded value can be used by prepending `:` to the desired + class name: `:class-name-to-always-apply`. + + ```handlebars + + ``` + + Results in the following rendered output: + + ```html + + ``` + + All three strategies - string return value, boolean return value, and + hard-coded value – can be combined in a single declaration: + + ```handlebars + + ``` + + @method bind-attr + @for Ember.Handlebars.helpers + @param {Hash} options + @return {String} HTML string + */ + function bindAttrHelper(options) { + var attrs = options.hash; + + Ember.assert("You must specify at least one hash argument to bind-attr", !!keys(attrs).length); + + var view = options.data.view; + var ret = []; + + // we relied on the behavior of calling without + // context to mean this === window, but when running + // "use strict", it's possible for this to === undefined; + var ctx = this || window; + + // Generate a unique id for this element. This will be added as a + // data attribute to the element so it can be looked up when + // the bound property changes. + var dataId = uuid(); + + // Handle classes differently, as we can bind multiple classes + var classBindings = attrs['class']; + if (classBindings != null) { + var classResults = bindClasses(ctx, classBindings, view, dataId, options); + + ret.push('class="' + Handlebars.Utils.escapeExpression(classResults.join(' ')) + '"'); + delete attrs['class']; + } + + var attrKeys = keys(attrs); + + // For each attribute passed, create an observer and emit the + // current value of the property as an attribute. + forEach.call(attrKeys, function(attr) { + var path = attrs[attr], + normalized; + + Ember.assert(fmt("You must provide an expression as the value of bound attribute. You specified: %@=%@", [attr, path]), typeof path === 'string'); + + normalized = normalizePath(ctx, path, options.data); + + var value = (path === 'this') ? normalized.root : handlebarsGet(ctx, path, options), + type = typeOf(value); + + Ember.assert(fmt("Attributes must be numbers, strings or booleans, not %@", [value]), value === null || value === undefined || type === 'number' || type === 'string' || type === 'boolean'); + + var observer; + + observer = function observer() { + var result = handlebarsGet(ctx, path, options); + + Ember.assert(fmt("Attributes must be numbers, strings or booleans, not %@", [result]), + result === null || result === undefined || typeof result === 'number' || + typeof result === 'string' || typeof result === 'boolean'); + + var elem = view.$("[data-bindattr-" + dataId + "='" + dataId + "']"); + + // If we aren't able to find the element, it means the element + // to which we were bound has been removed from the view. + // In that case, we can assume the template has been re-rendered + // and we need to clean up the observer. + if (!elem || elem.length === 0) { + removeObserver(normalized.root, normalized.path, observer); + return; + } + + View.applyAttributeBindings(elem, attr, result); + }; + + // Add an observer to the view for when the property changes. + // When the observer fires, find the element using the + // unique data id and update the attribute to the new value. + // Note: don't add observer when path is 'this' or path + // is whole keyword e.g. {{#each x in list}} ... {{bind-attr attr="x"}} + if (path !== 'this' && !(normalized.isKeyword && normalized.path === '' )) { + view.registerObserver(normalized.root, normalized.path, observer); + } + + // if this changes, also change the logic in ember-views/lib/views/view.js + if ((type === 'string' || (type === 'number' && !isNaN(value)))) { + ret.push(attr + '="' + Handlebars.Utils.escapeExpression(value) + '"'); + } else if (value && type === 'boolean') { + // The developer controls the attr name, so it should always be safe + ret.push(attr + '="' + attr + '"'); + } + }, this); + + // Add the unique identifier + // NOTE: We use all lower-case since Firefox has problems with mixed case in SVG + ret.push('data-bindattr-' + dataId + '="' + dataId + '"'); + return new SafeString(ret.join(' ')); + } + + /** + See `bind-attr` + + @method bindAttr + @for Ember.Handlebars.helpers + @deprecated + @param {Function} context + @param {Hash} options + @return {String} HTML string + */ + function bindAttrHelperDeprecated() { + Ember.warn("The 'bindAttr' view helper is deprecated in favor of 'bind-attr'"); + return helpers['bind-attr'].apply(this, arguments); + } + + /** + Helper that, given a space-separated string of property paths and a context, + returns an array of class names. Calling this method also has the side + effect of setting up observers at those property paths, such that if they + change, the correct class name will be reapplied to the DOM element. + + For example, if you pass the string "fooBar", it will first look up the + "fooBar" value of the context. If that value is true, it will add the + "foo-bar" class to the current element (i.e., the dasherized form of + "fooBar"). If the value is a string, it will add that string as the class. + Otherwise, it will not add any new class name. + + @private + @method bindClasses + @for Ember.Handlebars + @param {Ember.Object} context The context from which to lookup properties + @param {String} classBindings A string, space-separated, of class bindings + to use + @param {View} view The view in which observers should look for the + element to update + @param {Srting} bindAttrId Optional bindAttr id used to lookup elements + @return {Array} An array of class names to add + */ + function bindClasses(context, classBindings, view, bindAttrId, options) { + var ret = [], newClass, value, elem; + + // Helper method to retrieve the property from the context and + // determine which class string to return, based on whether it is + // a Boolean or not. + var classStringForPath = function(root, parsedPath, options) { + var val, + path = parsedPath.path; + + if (path === 'this') { + val = root; + } else if (path === '') { + val = true; + } else { + val = handlebarsGet(root, path, options); + } + + return View._classStringForValue(path, val, parsedPath.className, parsedPath.falsyClassName); + }; + + // For each property passed, loop through and setup + // an observer. + forEach.call(classBindings.split(' '), function(binding) { + + // Variable in which the old class value is saved. The observer function + // closes over this variable, so it knows which string to remove when + // the property changes. + var oldClass; + + var observer; + + var parsedPath = View._parsePropertyPath(binding), + path = parsedPath.path, + pathRoot = context, + normalized; + + if (path !== '' && path !== 'this') { + normalized = normalizePath(context, path, options.data); + + pathRoot = normalized.root; + path = normalized.path; + } + + // Set up an observer on the context. If the property changes, toggle the + // class name. + observer = function() { + // Get the current value of the property + newClass = classStringForPath(context, parsedPath, options); + elem = bindAttrId ? view.$("[data-bindattr-" + bindAttrId + "='" + bindAttrId + "']") : view.$(); + + // If we can't find the element anymore, a parent template has been + // re-rendered and we've been nuked. Remove the observer. + if (!elem || elem.length === 0) { + removeObserver(pathRoot, path, observer); + } else { + // If we had previously added a class to the element, remove it. + if (oldClass) { + elem.removeClass(oldClass); + } + + // If necessary, add a new class. Make sure we keep track of it so + // it can be removed in the future. + if (newClass) { + elem.addClass(newClass); + oldClass = newClass; + } else { + oldClass = null; + } + } + }; + + if (path !== '' && path !== 'this') { + view.registerObserver(pathRoot, path, observer); + } + + // We've already setup the observer; now we just need to figure out the + // correct behavior right now on the first pass through. + value = classStringForPath(context, parsedPath, options); + + if (value) { + ret.push(value); + + // Make sure we save the current value so that it can be removed if the + // observer fires. + oldClass = value; + } + }); + + return ret; + } + + __exports__.bind = bind; + __exports__._triageMustacheHelper = _triageMustacheHelper; + __exports__.resolveHelper = resolveHelper; + __exports__.bindHelper = bindHelper; + __exports__.boundIfHelper = boundIfHelper; + __exports__.unboundIfHelper = unboundIfHelper; + __exports__.withHelper = withHelper; + __exports__.ifHelper = ifHelper; + __exports__.unlessHelper = unlessHelper; + __exports__.bindAttrHelper = bindAttrHelper; + __exports__.bindAttrHelperDeprecated = bindAttrHelperDeprecated; + __exports__.bindClasses = bindClasses; + }); +define("ember-handlebars/helpers/collection", + ["ember-metal/core","ember-metal/utils","ember-handlebars-compiler","ember-runtime/system/string","ember-metal/property_get","ember-handlebars/ext","ember-handlebars/helpers/view","ember-metal/computed","ember-views/views/collection_view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var Ember = __dependency1__["default"]; + // Ember.assert, Ember.deprecate + var inspect = __dependency2__.inspect; + + // var emberAssert = Ember.assert; + // emberDeprecate = Ember.deprecate; + + var EmberHandlebars = __dependency3__["default"]; + var helpers = EmberHandlebars.helpers; + + var fmt = __dependency4__.fmt; + var get = __dependency5__.get; + var handlebarsGet = __dependency6__.handlebarsGet; + var ViewHelper = __dependency7__.ViewHelper; + var computed = __dependency8__.computed; + var CollectionView = __dependency9__["default"]; + + var alias = computed.alias; + /** + `{{collection}}` is a `Ember.Handlebars` helper for adding instances of + `Ember.CollectionView` to a template. See [Ember.CollectionView](/api/classes/Ember.CollectionView.html) + for additional information on how a `CollectionView` functions. + + `{{collection}}`'s primary use is as a block helper with a `contentBinding` + option pointing towards an `Ember.Array`-compatible object. An `Ember.View` + instance will be created for each item in its `content` property. Each view + will have its own `content` property set to the appropriate item in the + collection. + + The provided block will be applied as the template for each item's view. + + Given an empty `` the following template: + + ```handlebars + {{#collection contentBinding="App.items"}} + Hi {{view.content.name}} + {{/collection}} + ``` + + And the following application code + + ```javascript + App = Ember.Application.create() + App.items = [ + Ember.Object.create({name: 'Dave'}), + Ember.Object.create({name: 'Mary'}), + Ember.Object.create({name: 'Sara'}) + ] + ``` + + Will result in the HTML structure below + + ```html +
    +
    Hi Dave
    +
    Hi Mary
    +
    Hi Sara
    +
    + ``` + + ### Blockless use in a collection + + If you provide an `itemViewClass` option that has its own `template` you can + omit the block. + + The following template: + + ```handlebars + {{collection contentBinding="App.items" itemViewClass="App.AnItemView"}} + ``` + + And application code + + ```javascript + App = Ember.Application.create(); + App.items = [ + Ember.Object.create({name: 'Dave'}), + Ember.Object.create({name: 'Mary'}), + Ember.Object.create({name: 'Sara'}) + ]; + + App.AnItemView = Ember.View.extend({ + template: Ember.Handlebars.compile("Greetings {{view.content.name}}") + }); + ``` + + Will result in the HTML structure below + + ```html +
    +
    Greetings Dave
    +
    Greetings Mary
    +
    Greetings Sara
    +
    + ``` + + ### Specifying a CollectionView subclass + + By default the `{{collection}}` helper will create an instance of + `Ember.CollectionView`. You can supply a `Ember.CollectionView` subclass to + the helper by passing it as the first argument: + + ```handlebars + {{#collection App.MyCustomCollectionClass contentBinding="App.items"}} + Hi {{view.content.name}} + {{/collection}} + ``` + + ### Forwarded `item.*`-named Options + + As with the `{{view}}`, helper options passed to the `{{collection}}` will be + set on the resulting `Ember.CollectionView` as properties. Additionally, + options prefixed with `item` will be applied to the views rendered for each + item (note the camelcasing): + + ```handlebars + {{#collection contentBinding="App.items" + itemTagName="p" + itemClassNames="greeting"}} + Howdy {{view.content.name}} + {{/collection}} + ``` + + Will result in the following HTML structure: + + ```html +
    +

    Howdy Dave

    +

    Howdy Mary

    +

    Howdy Sara

    +
    + ``` + + @method collection + @for Ember.Handlebars.helpers + @param {String} path + @param {Hash} options + @return {String} HTML string + @deprecated Use `{{each}}` helper instead. + */ + function collectionHelper(path, options) { + Ember.deprecate("Using the {{collection}} helper without specifying a class has been deprecated as the {{each}} helper now supports the same functionality.", path !== 'collection'); + + // If no path is provided, treat path param as options. + if (path && path.data && path.data.isRenderData) { + options = path; + path = undefined; + Ember.assert("You cannot pass more than one argument to the collection helper", arguments.length === 1); + } else { + Ember.assert("You cannot pass more than one argument to the collection helper", arguments.length === 2); + } + + var fn = options.fn; + var data = options.data; + var inverse = options.inverse; + var view = options.data.view; + + + var controller, container; + // If passed a path string, convert that into an object. + // Otherwise, just default to the standard class. + var collectionClass; + if (path) { + controller = data.keywords.controller; + container = controller && controller.container; + collectionClass = handlebarsGet(this, path, options) || container.lookupFactory('view:' + path); + Ember.assert(fmt("%@ #collection: Could not find collection class %@", [data.view, path]), !!collectionClass); + } + else { + collectionClass = CollectionView; + } + + var hash = options.hash, itemHash = {}, match; + + // Extract item view class if provided else default to the standard class + var collectionPrototype = collectionClass.proto(), itemViewClass; + + if (hash.itemView) { + controller = data.keywords.controller; + Ember.assert('You specified an itemView, but the current context has no ' + + 'container to look the itemView up in. This probably means ' + + 'that you created a view manually, instead of through the ' + + 'container. Instead, use container.lookup("view:viewName"), ' + + 'which will properly instantiate your view.', + controller && controller.container); + container = controller.container; + itemViewClass = container.lookupFactory('view:' + hash.itemView); + Ember.assert('You specified the itemView ' + hash.itemView + ", but it was " + + "not found at " + container.describe("view:" + hash.itemView) + + " (and it was not registered in the container)", !!itemViewClass); + } else if (hash.itemViewClass) { + itemViewClass = handlebarsGet(collectionPrototype, hash.itemViewClass, options); + } else { + itemViewClass = collectionPrototype.itemViewClass; + } + + Ember.assert(fmt("%@ #collection: Could not find itemViewClass %@", [data.view, itemViewClass]), !!itemViewClass); + + delete hash.itemViewClass; + delete hash.itemView; + + // Go through options passed to the {{collection}} helper and extract options + // that configure item views instead of the collection itself. + for (var prop in hash) { + if (hash.hasOwnProperty(prop)) { + match = prop.match(/^item(.)(.*)$/); + + if (match && prop !== 'itemController') { + // Convert itemShouldFoo -> shouldFoo + itemHash[match[1].toLowerCase() + match[2]] = hash[prop]; + // Delete from hash as this will end up getting passed to the + // {{view}} helper method. + delete hash[prop]; + } + } + } + + if (fn) { + itemHash.template = fn; + delete options.fn; + } + + var emptyViewClass; + if (inverse && inverse !== EmberHandlebars.VM.noop) { + emptyViewClass = get(collectionPrototype, 'emptyViewClass'); + emptyViewClass = emptyViewClass.extend({ + template: inverse, + tagName: itemHash.tagName + }); + } else if (hash.emptyViewClass) { + emptyViewClass = handlebarsGet(this, hash.emptyViewClass, options); + } + if (emptyViewClass) { hash.emptyView = emptyViewClass; } + + if (hash.keyword) { + itemHash._context = this; + } else { + itemHash._context = alias('content'); + } + + var viewOptions = ViewHelper.propertiesFromHTMLOptions({ data: data, hash: itemHash }, this); + hash.itemViewClass = itemViewClass.extend(viewOptions); + + options.helperName = options.helperName || 'collection'; + + return helpers.view.call(this, collectionClass, options); + } + + __exports__["default"] = collectionHelper; + }); +define("ember-handlebars/helpers/debug", + ["ember-metal/core","ember-metal/utils","ember-metal/logger","ember-metal/property_get","ember-handlebars/ext","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + /*jshint debug:true*/ + + /** + @module ember + @submodule ember-handlebars + */ + var Ember = __dependency1__["default"]; + // Ember.FEATURES, + var inspect = __dependency2__.inspect; + var Logger = __dependency3__["default"]; + + var get = __dependency4__.get; + var normalizePath = __dependency5__.normalizePath; + var handlebarsGet = __dependency5__.handlebarsGet; + + var a_slice = [].slice; + + /** + `log` allows you to output the value of variables in the current rendering + context. `log` also accepts primitive types such as strings or numbers. + + ```handlebars + {{log "myVariable:" myVariable }} + ``` + + @method log + @for Ember.Handlebars.helpers + @param {String} property + */ + function logHelper() { + var params = a_slice.call(arguments, 0, -1), + options = arguments[arguments.length - 1], + logger = Logger.log, + values = [], + allowPrimitives = true; + + for (var i = 0; i < params.length; i++) { + var type = options.types[i]; + + if (type === 'ID' || !allowPrimitives) { + var context = (options.contexts && options.contexts[i]) || this, + normalized = normalizePath(context, params[i], options.data); + + if (normalized.path === 'this') { + values.push(normalized.root); + } else { + values.push(handlebarsGet(normalized.root, normalized.path, options)); + } + } else { + values.push(params[i]); + } + } + + logger.apply(logger, values); + } + + /** + Execute the `debugger` statement in the current context. + + ```handlebars + {{debugger}} + ``` + + Before invoking the `debugger` statement, there + are a few helpful variables defined in the + body of this helper that you can inspect while + debugging that describe how and where this + helper was invoked: + + - templateContext: this is most likely a controller + from which this template looks up / displays properties + - typeOfTemplateContext: a string description of + what the templateContext is + + For example, if you're wondering why a value `{{foo}}` + isn't rendering as expected within a template, you + could place a `{{debugger}}` statement, and when + the `debugger;` breakpoint is hit, you can inspect + `templateContext`, determine if it's the object you + expect, and/or evaluate expressions in the console + to perform property lookups on the `templateContext`: + + ``` + > templateContext.get('foo') // -> "" + ``` + + @method debugger + @for Ember.Handlebars.helpers + @param {String} property + */ + function debuggerHelper(options) { + + // These are helpful values you can inspect while debugging. + var templateContext = this; + var typeOfTemplateContext = inspect(templateContext); + Ember.Logger.info('Use `this` to access the context of the calling template.'); + + debugger; + } + + __exports__.logHelper = logHelper; + __exports__.debuggerHelper = debuggerHelper; + }); +define("ember-handlebars/helpers/each", + ["ember-metal/core","ember-handlebars-compiler","ember-runtime/system/string","ember-metal/property_get","ember-metal/property_set","ember-views/views/collection_view","ember-metal/binding","ember-runtime/mixins/controller","ember-runtime/controllers/array_controller","ember-runtime/mixins/array","ember-runtime/copy","ember-metal/run_loop","ember-metal/events","ember-handlebars/ext","ember-metal/computed","ember-metal/observer","ember-handlebars/views/metamorph_view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __exports__) { + "use strict"; + + /** + @module ember + @submodule ember-handlebars + */ + var Ember = __dependency1__["default"]; + // Ember.assert;, Ember.K + // var emberAssert = Ember.assert, + var K = Ember.K; + + var EmberHandlebars = __dependency2__["default"]; + var helpers = EmberHandlebars.helpers; + + var fmt = __dependency3__.fmt; + var get = __dependency4__.get; + var set = __dependency5__.set; + var CollectionView = __dependency6__["default"]; + var Binding = __dependency7__.Binding; + var ControllerMixin = __dependency8__["default"]; + var ArrayController = __dependency9__["default"]; + var EmberArray = __dependency10__["default"]; + var copy = __dependency11__["default"]; + var run = __dependency12__["default"]; + var on = __dependency13__.on; + var handlebarsGet = __dependency14__.handlebarsGet; + var computed = __dependency15__.computed; + + var addObserver = __dependency16__.addObserver; + var removeObserver = __dependency16__.removeObserver; + var addBeforeObserver = __dependency16__.addBeforeObserver; + var removeBeforeObserver = __dependency16__.removeBeforeObserver; + + var _Metamorph = __dependency17__._Metamorph; + var _MetamorphView = __dependency17__._MetamorphView; + + var EachView = CollectionView.extend(_Metamorph, { + + init: function() { + var itemController = get(this, 'itemController'); + var binding; + + if (itemController) { + var controller = get(this, 'controller.container').lookupFactory('controller:array').create({ + _isVirtual: true, + parentController: get(this, 'controller'), + itemController: itemController, + target: get(this, 'controller'), + _eachView: this + }); + + this.disableContentObservers(function() { + set(this, 'content', controller); + binding = new Binding('content', '_eachView.dataSource').oneWay(); + binding.connect(controller); + }); + + set(this, '_arrayController', controller); + } else { + this.disableContentObservers(function() { + binding = new Binding('content', 'dataSource').oneWay(); + binding.connect(this); + }); + } + + return this._super(); + }, + + _assertArrayLike: function(content) { + Ember.assert(fmt("The value that #each loops over must be an Array. You " + + "passed %@, but it should have been an ArrayController", + [content.constructor]), + !ControllerMixin.detect(content) || + (content && content.isGenerated) || + content instanceof ArrayController); + Ember.assert(fmt("The value that #each loops over must be an Array. You passed %@", [(ControllerMixin.detect(content) && content.get('model') !== undefined) ? fmt("'%@' (wrapped in %@)", [content.get('model'), content]) : content]), EmberArray.detect(content)); + }, + + disableContentObservers: function(callback) { + removeBeforeObserver(this, 'content', null, '_contentWillChange'); + removeObserver(this, 'content', null, '_contentDidChange'); + + callback.call(this); + + addBeforeObserver(this, 'content', null, '_contentWillChange'); + addObserver(this, 'content', null, '_contentDidChange'); + }, + + itemViewClass: _MetamorphView, + emptyViewClass: _MetamorphView, + + createChildView: function(view, attrs) { + view = this._super(view, attrs); + + // At the moment, if a container view subclass wants + // to insert keywords, it is responsible for cloning + // the keywords hash. This will be fixed momentarily. + var keyword = get(this, 'keyword'); + var content = get(view, 'content'); + + if (keyword) { + var data = get(view, 'templateData'); + + data = copy(data); + data.keywords = view.cloneKeywords(); + set(view, 'templateData', data); + + // In this case, we do not bind, because the `content` of + // a #each item cannot change. + data.keywords[keyword] = content; + } + + // If {{#each}} is looping over an array of controllers, + // point each child view at their respective controller. + if (content && content.isController) { + set(view, 'controller', content); + } + + return view; + }, + + destroy: function() { + if (!this._super()) { return; } + + var arrayController = get(this, '_arrayController'); + + if (arrayController) { + arrayController.destroy(); + } + + return this; + } + }); + + // Defeatureify doesn't seem to like nested functions that need to be removed + function _addMetamorphCheck() { + EachView.reopen({ + _checkMetamorph: on('didInsertElement', function() { + Ember.assert("The metamorph tags, " + + this.morph.start + " and " + this.morph.end + + ", have different parents.\nThe browser has fixed your template to output valid HTML (for example, check that you have properly closed all tags and have used a TBODY tag when creating a table with '{{#each}}')", + document.getElementById( this.morph.start ).parentNode === + document.getElementById( this.morph.end ).parentNode + ); + }) + }); + } + + // until ember-debug is es6ed + var runInDebug = function(f){ f(); }; + runInDebug( function() { + _addMetamorphCheck(); + }); + + var GroupedEach = EmberHandlebars.GroupedEach = function(context, path, options) { + var self = this, + normalized = EmberHandlebars.normalizePath(context, path, options.data); + + this.context = context; + this.path = path; + this.options = options; + this.template = options.fn; + this.containingView = options.data.view; + this.normalizedRoot = normalized.root; + this.normalizedPath = normalized.path; + this.content = this.lookupContent(); + + this.addContentObservers(); + this.addArrayObservers(); + + this.containingView.on('willClearRender', function() { + self.destroy(); + }); + }; + + GroupedEach.prototype = { + contentWillChange: function() { + this.removeArrayObservers(); + }, + + contentDidChange: function() { + this.content = this.lookupContent(); + this.addArrayObservers(); + this.rerenderContainingView(); + }, + + contentArrayWillChange: K, + + contentArrayDidChange: function() { + this.rerenderContainingView(); + }, + + lookupContent: function() { + return handlebarsGet(this.normalizedRoot, this.normalizedPath, this.options); + }, + + addArrayObservers: function() { + if (!this.content) { return; } + + this.content.addArrayObserver(this, { + willChange: 'contentArrayWillChange', + didChange: 'contentArrayDidChange' + }); + }, + + removeArrayObservers: function() { + if (!this.content) { return; } + + this.content.removeArrayObserver(this, { + willChange: 'contentArrayWillChange', + didChange: 'contentArrayDidChange' + }); + }, + + addContentObservers: function() { + addBeforeObserver(this.normalizedRoot, this.normalizedPath, this, this.contentWillChange); + addObserver(this.normalizedRoot, this.normalizedPath, this, this.contentDidChange); + }, + + removeContentObservers: function() { + removeBeforeObserver(this.normalizedRoot, this.normalizedPath, this.contentWillChange); + removeObserver(this.normalizedRoot, this.normalizedPath, this.contentDidChange); + }, + + render: function() { + if (!this.content) { return; } + + var content = this.content, + contentLength = get(content, 'length'), + options = this.options, + data = options.data, + template = this.template; + + data.insideEach = true; + for (var i = 0; i < contentLength; i++) { + var context = content.objectAt(i); + options.data.keywords[options.hash.keyword] = context; + template(context, { data: data }); + } + }, + + rerenderContainingView: function() { + var self = this; + run.scheduleOnce('render', this, function() { + // It's possible it's been destroyed after we enqueued a re-render call. + if (!self.destroyed) { + self.containingView.rerender(); + } + }); + }, + + destroy: function() { + this.removeContentObservers(); + if (this.content) { + this.removeArrayObservers(); + } + this.destroyed = true; + } + }; + + /** + The `{{#each}}` helper loops over elements in a collection, rendering its + block once for each item. It is an extension of the base Handlebars `{{#each}}` + helper: + + ```javascript + Developers = [{name: 'Yehuda'},{name: 'Tom'}, {name: 'Paul'}]; + ``` + + ```handlebars + {{#each Developers}} + {{name}} + {{/each}} + ``` + + `{{each}}` supports an alternative syntax with element naming: + + ```handlebars + {{#each person in Developers}} + {{person.name}} + {{/each}} + ``` + + When looping over objects that do not have properties, `{{this}}` can be used + to render the object: + + ```javascript + DeveloperNames = ['Yehuda', 'Tom', 'Paul'] + ``` + + ```handlebars + {{#each DeveloperNames}} + {{this}} + {{/each}} + ``` + ### {{else}} condition + `{{#each}}` can have a matching `{{else}}`. The contents of this block will render + if the collection is empty. + + ``` + {{#each person in Developers}} + {{person.name}} + {{else}} +

    Sorry, nobody is available for this task.

    + {{/each}} + ``` + ### Specifying a View class for items + If you provide an `itemViewClass` option that references a view class + with its own `template` you can omit the block. + + The following template: + + ```handlebars + {{#view App.MyView }} + {{each view.items itemViewClass="App.AnItemView"}} + {{/view}} + ``` + + And application code + + ```javascript + App = Ember.Application.create({ + MyView: Ember.View.extend({ + items: [ + Ember.Object.create({name: 'Dave'}), + Ember.Object.create({name: 'Mary'}), + Ember.Object.create({name: 'Sara'}) + ] + }) + }); + + App.AnItemView = Ember.View.extend({ + template: Ember.Handlebars.compile("Greetings {{name}}") + }); + ``` + + Will result in the HTML structure below + + ```html +
    +
    Greetings Dave
    +
    Greetings Mary
    +
    Greetings Sara
    +
    + ``` + + If an `itemViewClass` is defined on the helper, and therefore the helper is not + being used as a block, an `emptyViewClass` can also be provided optionally. + The `emptyViewClass` will match the behavior of the `{{else}}` condition + described above. That is, the `emptyViewClass` will render if the collection + is empty. + + ### Representing each item with a Controller. + By default the controller lookup within an `{{#each}}` block will be + the controller of the template where the `{{#each}}` was used. If each + item needs to be presented by a custom controller you can provide a + `itemController` option which references a controller by lookup name. + Each item in the loop will be wrapped in an instance of this controller + and the item itself will be set to the `model` property of that controller. + + This is useful in cases where properties of model objects need transformation + or synthesis for display: + + ```javascript + App.DeveloperController = Ember.ObjectController.extend({ + isAvailableForHire: function() { + return !this.get('model.isEmployed') && this.get('model.isSeekingWork'); + }.property('isEmployed', 'isSeekingWork') + }) + ``` + + ```handlebars + {{#each person in developers itemController="developer"}} + {{person.name}} {{#if person.isAvailableForHire}}Hire me!{{/if}} + {{/each}} + ``` + + Each itemController will receive a reference to the current controller as + a `parentController` property. + + ### (Experimental) Grouped Each + + When used in conjunction with the experimental [group helper](https://github.com/emberjs/group-helper), + you can inform Handlebars to re-render an entire group of items instead of + re-rendering them one at a time (in the event that they are changed en masse + or an item is added/removed). + + ```handlebars + {{#group}} + {{#each people}} + {{firstName}} {{lastName}} + {{/each}} + {{/group}} + ``` + + This can be faster than the normal way that Handlebars re-renders items + in some cases. + + If for some reason you have a group with more than one `#each`, you can make + one of the collections be updated in normal (non-grouped) fashion by setting + the option `groupedRows=true` (counter-intuitive, I know). + + For example, + + ```handlebars + {{dealershipName}} + + {{#group}} + {{#each dealers}} + {{firstName}} {{lastName}} + {{/each}} + + {{#each car in cars groupedRows=true}} + {{car.make}} {{car.model}} {{car.color}} + {{/each}} + {{/group}} + ``` + Any change to `dealershipName` or the `dealers` collection will cause the + entire group to be re-rendered. However, changes to the `cars` collection + will be re-rendered individually (as normal). + + Note that `group` behavior is also disabled by specifying an `itemViewClass`. + + @method each + @for Ember.Handlebars.helpers + @param [name] {String} name for item (used with `in`) + @param [path] {String} path + @param [options] {Object} Handlebars key/value pairs of options + @param [options.itemViewClass] {String} a path to a view class used for each item + @param [options.itemController] {String} name of a controller to be created for each item + @param [options.groupedRows] {boolean} enable normal item-by-item rendering when inside a `#group` helper + */ + function eachHelper(path, options) { + var ctx, helperName = 'each'; + + if (arguments.length === 4) { + Ember.assert("If you pass more than one argument to the each helper, it must be in the form #each foo in bar", arguments[1] === "in"); + + var keywordName = arguments[0]; + + + options = arguments[3]; + path = arguments[2]; + + helperName += ' ' + keywordName + ' in ' + path; + + if (path === '') { path = "this"; } + + options.hash.keyword = keywordName; + + } else if (arguments.length === 1) { + options = path; + path = 'this'; + } else { + helperName += ' ' + path; + } + + options.hash.dataSourceBinding = path; + // Set up emptyView as a metamorph with no tag + //options.hash.emptyViewClass = Ember._MetamorphView; + + // can't rely on this default behavior when use strict + ctx = this || window; + + options.helperName = options.helperName || helperName; + + if (options.data.insideGroup && !options.hash.groupedRows && !options.hash.itemViewClass) { + new GroupedEach(ctx, path, options).render(); + } else { + // ES6TODO: figure out how to do this without global lookup. + return helpers.collection.call(ctx, 'Ember.Handlebars.EachView', options); + } + } + + __exports__.EachView = EachView; + __exports__.GroupedEach = GroupedEach; + __exports__.eachHelper = eachHelper; + }); +define("ember-handlebars/helpers/loc", + ["ember-runtime/system/string","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var loc = __dependency1__.loc; + + /** + @module ember + @submodule ember-handlebars + */ + + // ES6TODO: + // Pretty sure this can be expressed as + // var locHelper EmberStringUtils.loc ? + + /** + Calls [Ember.String.loc](/api/classes/Ember.String.html#method_loc) with the + provided string. + + This is a convenient way to localize text. For example: + + ```html + + ``` + + Take note that `"welcome"` is a string and not an object + reference. + + See [Ember.String.loc](/api/classes/Ember.String.html#method_loc) for how to + set up localized string references. + + @method loc + @for Ember.Handlebars.helpers + @param {String} str The string to format + @see {Ember.String#loc} + */ + __exports__["default"] = function locHelper(str) { + return loc(str); + } + }); +define("ember-handlebars/helpers/partial", + ["ember-metal/core","ember-metal/is_none","ember-handlebars/ext","ember-handlebars/helpers/binding","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert + // var emberAssert = Ember.assert; + + var isNone = __dependency2__.isNone; + var handlebarsGet = __dependency3__.handlebarsGet; + var bind = __dependency4__.bind; + + /** + @module ember + @submodule ember-handlebars + */ + + /** + The `partial` helper renders another template without + changing the template context: + + ```handlebars + {{foo}} + {{partial "nav"}} + ``` + + The above example template will render a template named + "_nav", which has the same context as the parent template + it's rendered into, so if the "_nav" template also referenced + `{{foo}}`, it would print the same thing as the `{{foo}}` + in the above example. + + If a "_nav" template isn't found, the `partial` helper will + fall back to a template named "nav". + + ## Bound template names + + The parameter supplied to `partial` can also be a path + to a property containing a template name, e.g.: + + ```handlebars + {{partial someTemplateName}} + ``` + + The above example will look up the value of `someTemplateName` + on the template context (e.g. a controller) and use that + value as the name of the template to render. If the resolved + value is falsy, nothing will be rendered. If `someTemplateName` + changes, the partial will be re-rendered using the new template + name. + + ## Setting the partial's context with `with` + + The `partial` helper can be used in conjunction with the `with` + helper to set a context that will be used by the partial: + + ```handlebars + {{#with currentUser}} + {{partial "user_info"}} + {{/with}} + ``` + + @method partial + @for Ember.Handlebars.helpers + @param {String} partialName the name of the template to render minus the leading underscore + */ + + __exports__["default"] = function partialHelper(name, options) { + + var context = (options.contexts && options.contexts.length) ? options.contexts[0] : this; + + options.helperName = options.helperName || 'partial'; + + if (options.types[0] === "ID") { + // Helper was passed a property path; we need to + // create a binding that will re-render whenever + // this property changes. + options.fn = function(context, fnOptions) { + var partialName = handlebarsGet(context, name, fnOptions); + renderPartial(context, partialName, fnOptions); + }; + + return bind.call(context, name, options, true, exists); + } else { + // Render the partial right into parent template. + renderPartial(context, name, options); + } + } + + function exists(value) { + return !isNone(value); + } + + function renderPartial(context, name, options) { + var nameParts = name.split("/"); + var lastPart = nameParts[nameParts.length - 1]; + + nameParts[nameParts.length - 1] = "_" + lastPart; + + var view = options.data.view; + var underscoredName = nameParts.join("/"); + var template = view.templateForName(underscoredName); + var deprecatedTemplate = !template && view.templateForName(name); + + Ember.assert("Unable to find partial with name '"+name+"'.", template || deprecatedTemplate); + + template = template || deprecatedTemplate; + + template(context, { data: options.data }); + } + }); +define("ember-handlebars/helpers/shared", + ["ember-handlebars/ext","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var handlebarsGet = __dependency1__.handlebarsGet; + + __exports__["default"] = function resolvePaths(options) { + var ret = [], + contexts = options.contexts, + roots = options.roots, + data = options.data; + + for (var i=0, l=contexts.length; i + {{#with loggedInUser}} + Last Login: {{lastLogin}} + User Info: {{template "user_info"}} + {{/with}} + + ``` + + ```html + + ``` + + ```handlebars + {{#if isUser}} + {{template "user_info"}} + {{else}} + {{template "unlogged_user_info"}} + {{/if}} + ``` + + This helper looks for templates in the global `Ember.TEMPLATES` hash. If you + add `"; + return testEl.firstChild.innerHTML === ''; + })(); + + // IE 8 (and likely earlier) likes to move whitespace preceeding + // a script tag to appear after it. This means that we can + // accidentally remove whitespace when updating a morph. + var movesWhitespace = typeof document !== 'undefined' && (function() { + var testEl = document.createElement('div'); + testEl.innerHTML = "Test: Value"; + return testEl.childNodes[0].nodeValue === 'Test:' && + testEl.childNodes[2].nodeValue === ' Value'; + })(); + + // Use this to find children by ID instead of using jQuery + var findChildById = function(element, id) { + if (element.getAttribute('id') === id) { return element; } + + var len = element.childNodes.length, idx, node, found; + for (idx=0; idx 0) { + var len = matches.length, idx; + for (idx=0; idxTest'); + canSet = el.options.length === 1; + } + + innerHTMLTags[tagName] = canSet; + + return canSet; + }; + + function setInnerHTML(element, html) { + var tagName = element.tagName; + + if (canSetInnerHTML(tagName)) { + setInnerHTMLWithoutFix(element, html); + } else { + // Firefox versions < 11 do not have support for element.outerHTML. + var outerHTML = element.outerHTML || new XMLSerializer().serializeToString(element); + Ember.assert("Can't set innerHTML on "+element.tagName+" in this browser", outerHTML); + + var startTag = outerHTML.match(new RegExp("<"+tagName+"([^>]*)>", 'i'))[0], + endTag = ''; + + var wrapper = document.createElement('div'); + setInnerHTMLWithoutFix(wrapper, startTag + html + endTag); + element = wrapper.firstChild; + while (element.tagName !== tagName) { + element = element.nextSibling; + } + } + + return element; + } + + __exports__.setInnerHTML = setInnerHTML;function isSimpleClick(event) { + var modifier = event.shiftKey || event.metaKey || event.altKey || event.ctrlKey, + secondaryClick = event.which > 1; // IE9 may return undefined + + return !modifier && !secondaryClick; + } + + __exports__.isSimpleClick = isSimpleClick; + }); +define("ember-views/views/collection_view", + ["ember-metal/core","ember-metal/platform","ember-metal/binding","ember-metal/merge","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/string","ember-views/views/container_view","ember-views/views/core_view","ember-views/views/view","ember-metal/mixin","ember-runtime/mixins/array","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { + "use strict"; + + /** + @module ember + @submodule ember-views + */ + + var Ember = __dependency1__["default"]; + // Ember.assert + var create = __dependency2__.create; + var isGlobalPath = __dependency3__.isGlobalPath; + var merge = __dependency4__["default"]; + var get = __dependency5__.get; + var set = __dependency6__.set; + var fmt = __dependency7__.fmt; + var ContainerView = __dependency8__["default"]; + var CoreView = __dependency9__["default"]; + var View = __dependency10__["default"]; + var observer = __dependency11__.observer; + var beforeObserver = __dependency11__.beforeObserver; + var EmberArray = __dependency12__["default"]; + + /** + `Ember.CollectionView` is an `Ember.View` descendent responsible for managing + a collection (an array or array-like object) by maintaining a child view object + and associated DOM representation for each item in the array and ensuring + that child views and their associated rendered HTML are updated when items in + the array are added, removed, or replaced. + + ## Setting content + + The managed collection of objects is referenced as the `Ember.CollectionView` + instance's `content` property. + + ```javascript + someItemsView = Ember.CollectionView.create({ + content: ['A', 'B','C'] + }) + ``` + + The view for each item in the collection will have its `content` property set + to the item. + + ## Specifying itemViewClass + + By default the view class for each item in the managed collection will be an + instance of `Ember.View`. You can supply a different class by setting the + `CollectionView`'s `itemViewClass` property. + + Given an empty `` and the following code: + + ```javascript + someItemsView = Ember.CollectionView.create({ + classNames: ['a-collection'], + content: ['A','B','C'], + itemViewClass: Ember.View.extend({ + template: Ember.Handlebars.compile("the letter: {{view.content}}") + }) + }); + + someItemsView.appendTo('body'); + ``` + + Will result in the following HTML structure + + ```html +
    +
    the letter: A
    +
    the letter: B
    +
    the letter: C
    +
    + ``` + + ## Automatic matching of parent/child tagNames + + Setting the `tagName` property of a `CollectionView` to any of + "ul", "ol", "table", "thead", "tbody", "tfoot", "tr", or "select" will result + in the item views receiving an appropriately matched `tagName` property. + + Given an empty `` and the following code: + + ```javascript + anUnorderedListView = Ember.CollectionView.create({ + tagName: 'ul', + content: ['A','B','C'], + itemViewClass: Ember.View.extend({ + template: Ember.Handlebars.compile("the letter: {{view.content}}") + }) + }); + + anUnorderedListView.appendTo('body'); + ``` + + Will result in the following HTML structure + + ```html +
      +
    • the letter: A
    • +
    • the letter: B
    • +
    • the letter: C
    • +
    + ``` + + Additional `tagName` pairs can be provided by adding to + `Ember.CollectionView.CONTAINER_MAP ` + + ```javascript + Ember.CollectionView.CONTAINER_MAP['article'] = 'section' + ``` + + ## Programmatic creation of child views + + For cases where additional customization beyond the use of a single + `itemViewClass` or `tagName` matching is required CollectionView's + `createChildView` method can be overidden: + + ```javascript + CustomCollectionView = Ember.CollectionView.extend({ + createChildView: function(viewClass, attrs) { + if (attrs.content.kind == 'album') { + viewClass = App.AlbumView; + } else { + viewClass = App.SongView; + } + return this._super(viewClass, attrs); + } + }); + ``` + + ## Empty View + + You can provide an `Ember.View` subclass to the `Ember.CollectionView` + instance as its `emptyView` property. If the `content` property of a + `CollectionView` is set to `null` or an empty array, an instance of this view + will be the `CollectionView`s only child. + + ```javascript + aListWithNothing = Ember.CollectionView.create({ + classNames: ['nothing'] + content: null, + emptyView: Ember.View.extend({ + template: Ember.Handlebars.compile("The collection is empty") + }) + }); + + aListWithNothing.appendTo('body'); + ``` + + Will result in the following HTML structure + + ```html +
    +
    + The collection is empty +
    +
    + ``` + + ## Adding and Removing items + + The `childViews` property of a `CollectionView` should not be directly + manipulated. Instead, add, remove, replace items from its `content` property. + This will trigger appropriate changes to its rendered HTML. + + + @class CollectionView + @namespace Ember + @extends Ember.ContainerView + @since Ember 0.9 + */ + var CollectionView = ContainerView.extend({ + + /** + A list of items to be displayed by the `Ember.CollectionView`. + + @property content + @type Ember.Array + @default null + */ + content: null, + + /** + This provides metadata about what kind of empty view class this + collection would like if it is being instantiated from another + system (like Handlebars) + + @private + @property emptyViewClass + */ + emptyViewClass: View, + + /** + An optional view to display if content is set to an empty array. + + @property emptyView + @type Ember.View + @default null + */ + emptyView: null, + + /** + @property itemViewClass + @type Ember.View + @default Ember.View + */ + itemViewClass: View, + + /** + Setup a CollectionView + + @method init + */ + init: function() { + var ret = this._super(); + this._contentDidChange(); + return ret; + }, + + /** + Invoked when the content property is about to change. Notifies observers that the + entire array content will change. + + @private + @method _contentWillChange + */ + _contentWillChange: beforeObserver('content', function() { + var content = this.get('content'); + + if (content) { content.removeArrayObserver(this); } + var len = content ? get(content, 'length') : 0; + this.arrayWillChange(content, 0, len); + }), + + /** + Check to make sure that the content has changed, and if so, + update the children directly. This is always scheduled + asynchronously, to allow the element to be created before + bindings have synchronized and vice versa. + + @private + @method _contentDidChange + */ + _contentDidChange: observer('content', function() { + var content = get(this, 'content'); + + if (content) { + this._assertArrayLike(content); + content.addArrayObserver(this); + } + + var len = content ? get(content, 'length') : 0; + this.arrayDidChange(content, 0, null, len); + }), + + /** + Ensure that the content implements Ember.Array + + @private + @method _assertArrayLike + */ + _assertArrayLike: function(content) { + Ember.assert(fmt("an Ember.CollectionView's content must implement Ember.Array. You passed %@", [content]), EmberArray.detect(content)); + }, + + /** + Removes the content and content observers. + + @method destroy + */ + destroy: function() { + if (!this._super()) { return; } + + var content = get(this, 'content'); + if (content) { content.removeArrayObserver(this); } + + if (this._createdEmptyView) { + this._createdEmptyView.destroy(); + } + + return this; + }, + + /** + Called when a mutation to the underlying content array will occur. + + This method will remove any views that are no longer in the underlying + content array. + + Invokes whenever the content array itself will change. + + @method arrayWillChange + @param {Array} content the managed collection of objects + @param {Number} start the index at which the changes will occurr + @param {Number} removed number of object to be removed from content + */ + arrayWillChange: function(content, start, removedCount) { + // If the contents were empty before and this template collection has an + // empty view remove it now. + var emptyView = get(this, 'emptyView'); + if (emptyView && emptyView instanceof View) { + emptyView.removeFromParent(); + } + + // Loop through child views that correspond with the removed items. + // Note that we loop from the end of the array to the beginning because + // we are mutating it as we go. + var childViews = this._childViews, childView, idx, len; + + len = this._childViews.length; + + var removingAll = removedCount === len; + + if (removingAll) { + this.currentState.empty(this); + this.invokeRecursively(function(view) { + view.removedFromDOM = true; + }, false); + } + + for (idx = start + removedCount - 1; idx >= start; idx--) { + childView = childViews[idx]; + childView.destroy(); + } + }, + + /** + Called when a mutation to the underlying content array occurs. + + This method will replay that mutation against the views that compose the + `Ember.CollectionView`, ensuring that the view reflects the model. + + This array observer is added in `contentDidChange`. + + @method arrayDidChange + @param {Array} content the managed collection of objects + @param {Number} start the index at which the changes occurred + @param {Number} removed number of object removed from content + @param {Number} added number of object added to content + */ + arrayDidChange: function(content, start, removed, added) { + var addedViews = [], view, item, idx, len, itemViewClass, + emptyView; + + len = content ? get(content, 'length') : 0; + + if (len) { + itemViewClass = get(this, 'itemViewClass'); + + if ('string' === typeof itemViewClass && isGlobalPath(itemViewClass)) { + itemViewClass = get(itemViewClass) || itemViewClass; + } + + Ember.assert(fmt("itemViewClass must be a subclass of Ember.View, not %@", + [itemViewClass]), + 'string' === typeof itemViewClass || View.detect(itemViewClass)); + + for (idx = start; idx < start+added; idx++) { + item = content.objectAt(idx); + + view = this.createChildView(itemViewClass, { + content: item, + contentIndex: idx + }); + + addedViews.push(view); + } + } else { + emptyView = get(this, 'emptyView'); + + if (!emptyView) { return; } + + if ('string' === typeof emptyView && isGlobalPath(emptyView)) { + emptyView = get(emptyView) || emptyView; + } + + emptyView = this.createChildView(emptyView); + addedViews.push(emptyView); + set(this, 'emptyView', emptyView); + + if (CoreView.detect(emptyView)) { + this._createdEmptyView = emptyView; + } + } + + this.replace(start, 0, addedViews); + }, + + /** + Instantiates a view to be added to the childViews array during view + initialization. You generally will not call this method directly unless + you are overriding `createChildViews()`. Note that this method will + automatically configure the correct settings on the new view instance to + act as a child of the parent. + + The tag name for the view will be set to the tagName of the viewClass + passed in. + + @method createChildView + @param {Class} viewClass + @param {Hash} [attrs] Attributes to add + @return {Ember.View} new instance + */ + createChildView: function(view, attrs) { + view = this._super(view, attrs); + + var itemTagName = get(view, 'tagName'); + + if (itemTagName === null || itemTagName === undefined) { + itemTagName = CollectionView.CONTAINER_MAP[get(this, 'tagName')]; + set(view, 'tagName', itemTagName); + } + + return view; + } + }); + + /** + A map of parent tags to their default child tags. You can add + additional parent tags if you want collection views that use + a particular parent tag to default to a child tag. + + @property CONTAINER_MAP + @type Hash + @static + @final + */ + CollectionView.CONTAINER_MAP = { + ul: 'li', + ol: 'li', + table: 'tr', + thead: 'tr', + tbody: 'tr', + tfoot: 'tr', + tr: 'td', + select: 'option' + }; + + __exports__["default"] = CollectionView; + }); +define("ember-views/views/component", + ["ember-metal/core","ember-views/mixins/component_template_deprecation","ember-runtime/mixins/target_action_support","ember-views/views/view","ember-metal/property_get","ember-metal/property_set","ember-metal/is_none","ember-metal/computed","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert, Ember.Handlebars + + var ComponentTemplateDeprecation = __dependency2__["default"]; + var TargetActionSupport = __dependency3__["default"]; + var View = __dependency4__["default"]; + + var get = __dependency5__.get; + var set = __dependency6__.set; + var isNone = __dependency7__.isNone; + + var computed = __dependency8__.computed; + + var a_slice = Array.prototype.slice; + + /** + @module ember + @submodule ember-views + */ + + /** + An `Ember.Component` is a view that is completely + isolated. Property access in its templates go + to the view object and actions are targeted at + the view object. There is no access to the + surrounding context or outer controller; all + contextual information must be passed in. + + The easiest way to create an `Ember.Component` is via + a template. If you name a template + `components/my-foo`, you will be able to use + `{{my-foo}}` in other templates, which will make + an instance of the isolated component. + + ```handlebars + {{app-profile person=currentUser}} + ``` + + ```handlebars + +

    {{person.title}}

    + +

    {{person.signature}}

    + ``` + + You can use `yield` inside a template to + include the **contents** of any block attached to + the component. The block will be executed in the + context of the surrounding context or outer controller: + + ```handlebars + {{#app-profile person=currentUser}} +

    Admin mode

    + {{! Executed in the controller's context. }} + {{/app-profile}} + ``` + + ```handlebars + +

    {{person.title}}

    + {{! Executed in the components context. }} + {{yield}} {{! block contents }} + ``` + + If you want to customize the component, in order to + handle events or actions, you implement a subclass + of `Ember.Component` named after the name of the + component. Note that `Component` needs to be appended to the name of + your subclass like `AppProfileComponent`. + + For example, you could implement the action + `hello` for the `app-profile` component: + + ```javascript + App.AppProfileComponent = Ember.Component.extend({ + actions: { + hello: function(name) { + console.log("Hello", name); + } + } + }); + ``` + + And then use it in the component's template: + + ```handlebars + + +

    {{person.title}}

    + {{yield}} + + + ``` + + Components must have a `-` in their name to avoid + conflicts with built-in controls that wrap HTML + elements. This is consistent with the same + requirement in web components. + + @class Component + @namespace Ember + @extends Ember.View + */ + var Component = View.extend(TargetActionSupport, ComponentTemplateDeprecation, { + instrumentName: 'component', + instrumentDisplay: computed(function() { + if (this._debugContainerKey) { + return '{{' + this._debugContainerKey.split(':')[1] + '}}'; + } + }), + + init: function() { + this._super(); + set(this, 'origContext', get(this, 'context')); + set(this, 'context', this); + set(this, 'controller', this); + }, + + defaultLayout: function(context, options){ + Ember.Handlebars.helpers['yield'].call(context, options); + }, + + /** + A components template property is set by passing a block + during its invocation. It is executed within the parent context. + + Example: + + ```handlebars + {{#my-component}} + // something that is run in the context + // of the parent context + {{/my-component}} + ``` + + Specifying a template directly to a component is deprecated without + also specifying the layout property. + + @deprecated + @property template + */ + template: computed(function(key, value) { + if (value !== undefined) { return value; } + + var templateName = get(this, 'templateName'), + template = this.templateForName(templateName, 'template'); + + Ember.assert("You specified the templateName " + templateName + " for " + this + ", but it did not exist.", !templateName || template); + + return template || get(this, 'defaultTemplate'); + }).property('templateName'), + + /** + Specifying a components `templateName` is deprecated without also + providing the `layout` or `layoutName` properties. + + @deprecated + @property templateName + */ + templateName: null, + + // during render, isolate keywords + cloneKeywords: function() { + return { + view: this, + controller: this + }; + }, + + _yield: function(context, options) { + var view = options.data.view, + parentView = this._parentView, + template = get(this, 'template'); + + if (template) { + Ember.assert("A Component must have a parent view in order to yield.", parentView); + + view.appendChild(View, { + isVirtual: true, + tagName: '', + _contextView: parentView, + template: template, + context: options.data.insideGroup ? get(this, 'origContext') : get(parentView, 'context'), + controller: get(parentView, 'controller'), + templateData: { keywords: parentView.cloneKeywords(), insideGroup: options.data.insideGroup } + }); + } + }, + + /** + If the component is currently inserted into the DOM of a parent view, this + property will point to the controller of the parent view. + + @property targetObject + @type Ember.Controller + @default null + */ + targetObject: computed(function(key) { + var parentView = get(this, '_parentView'); + return parentView ? get(parentView, 'controller') : null; + }).property('_parentView'), + + /** + Triggers a named action on the controller context where the component is used if + this controller has registered for notifications of the action. + + For example a component for playing or pausing music may translate click events + into action notifications of "play" or "stop" depending on some internal state + of the component: + + + ```javascript + App.PlayButtonComponent = Ember.Component.extend({ + click: function(){ + if (this.get('isPlaying')) { + this.sendAction('play'); + } else { + this.sendAction('stop'); + } + } + }); + ``` + + When used inside a template these component actions are configured to + trigger actions in the outer application context: + + ```handlebars + {{! application.hbs }} + {{play-button play="musicStarted" stop="musicStopped"}} + ``` + + When the component receives a browser `click` event it translate this + interaction into application-specific semantics ("play" or "stop") and + triggers the specified action name on the controller for the template + where the component is used: + + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + actions: { + musicStarted: function(){ + // called when the play button is clicked + // and the music started playing + }, + musicStopped: function(){ + // called when the play button is clicked + // and the music stopped playing + } + } + }); + ``` + + If no action name is passed to `sendAction` a default name of "action" + is assumed. + + ```javascript + App.NextButtonComponent = Ember.Component.extend({ + click: function(){ + this.sendAction(); + } + }); + ``` + + ```handlebars + {{! application.hbs }} + {{next-button action="playNextSongInAlbum"}} + ``` + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + actions: { + playNextSongInAlbum: function(){ + ... + } + } + }); + ``` + + @method sendAction + @param [action] {String} the action to trigger + @param [context] {*} a context to send with the action + */ + sendAction: function(action) { + var actionName, + contexts = a_slice.call(arguments, 1); + + // Send the default action + if (action === undefined) { + actionName = get(this, 'action'); + Ember.assert("The default action was triggered on the component " + this.toString() + + ", but the action name (" + actionName + ") was not a string.", + isNone(actionName) || typeof actionName === 'string'); + } else { + actionName = get(this, action); + Ember.assert("The " + action + " action was triggered on the component " + + this.toString() + ", but the action name (" + actionName + + ") was not a string.", + isNone(actionName) || typeof actionName === 'string'); + } + + // If no action name for that action could be found, just abort. + if (actionName === undefined) { return; } + + this.triggerAction({ + action: actionName, + actionContext: contexts + }); + } + }); + + __exports__["default"] = Component; + }); +define("ember-views/views/container_view", + ["ember-metal/core","ember-metal/merge","ember-runtime/mixins/mutable_array","ember-metal/property_get","ember-metal/property_set","ember-views/views/view","ember-views/views/view_collection","ember-views/views/states","ember-metal/error","ember-metal/enumerable_utils","ember-metal/computed","ember-metal/run_loop","ember-metal/properties","ember-views/system/render_buffer","ember-metal/mixin","ember-runtime/system/native_array","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert, Ember.K + + var merge = __dependency2__["default"]; + var MutableArray = __dependency3__["default"]; + var get = __dependency4__.get; + var set = __dependency5__.set; + + var View = __dependency6__["default"]; + var ViewCollection = __dependency7__["default"]; + + var cloneStates = __dependency8__.cloneStates; + var EmberViewStates = __dependency8__.states; + + var EmberError = __dependency9__["default"]; + + var forEach = __dependency10__.forEach; + + var computed = __dependency11__.computed; + var run = __dependency12__["default"]; + var defineProperty = __dependency13__.defineProperty; + var renderBuffer = __dependency14__["default"]; + var observer = __dependency15__.observer; + var beforeObserver = __dependency15__.beforeObserver; + var emberA = __dependency16__.A; + + /** + @module ember + @submodule ember-views + */ + + var states = cloneStates(EmberViewStates); + + /** + A `ContainerView` is an `Ember.View` subclass that implements `Ember.MutableArray` + allowing programmatic management of its child views. + + ## Setting Initial Child Views + + The initial array of child views can be set in one of two ways. You can + provide a `childViews` property at creation time that contains instance of + `Ember.View`: + + ```javascript + aContainer = Ember.ContainerView.create({ + childViews: [Ember.View.create(), Ember.View.create()] + }); + ``` + + You can also provide a list of property names whose values are instances of + `Ember.View`: + + ```javascript + aContainer = Ember.ContainerView.create({ + childViews: ['aView', 'bView', 'cView'], + aView: Ember.View.create(), + bView: Ember.View.create(), + cView: Ember.View.create() + }); + ``` + + The two strategies can be combined: + + ```javascript + aContainer = Ember.ContainerView.create({ + childViews: ['aView', Ember.View.create()], + aView: Ember.View.create() + }); + ``` + + Each child view's rendering will be inserted into the container's rendered + HTML in the same order as its position in the `childViews` property. + + ## Adding and Removing Child Views + + The container view implements `Ember.MutableArray` allowing programmatic management of its child views. + + To remove a view, pass that view into a `removeObject` call on the container view. + + Given an empty `` the following code + + ```javascript + aContainer = Ember.ContainerView.create({ + classNames: ['the-container'], + childViews: ['aView', 'bView'], + aView: Ember.View.create({ + template: Ember.Handlebars.compile("A") + }), + bView: Ember.View.create({ + template: Ember.Handlebars.compile("B") + }) + }); + + aContainer.appendTo('body'); + ``` + + Results in the HTML + + ```html +
    +
    A
    +
    B
    +
    + ``` + + Removing a view + + ```javascript + aContainer.toArray(); // [aContainer.aView, aContainer.bView] + aContainer.removeObject(aContainer.get('bView')); + aContainer.toArray(); // [aContainer.aView] + ``` + + Will result in the following HTML + + ```html +
    +
    A
    +
    + ``` + + Similarly, adding a child view is accomplished by adding `Ember.View` instances to the + container view. + + Given an empty `` the following code + + ```javascript + aContainer = Ember.ContainerView.create({ + classNames: ['the-container'], + childViews: ['aView', 'bView'], + aView: Ember.View.create({ + template: Ember.Handlebars.compile("A") + }), + bView: Ember.View.create({ + template: Ember.Handlebars.compile("B") + }) + }); + + aContainer.appendTo('body'); + ``` + + Results in the HTML + + ```html +
    +
    A
    +
    B
    +
    + ``` + + Adding a view + + ```javascript + AnotherViewClass = Ember.View.extend({ + template: Ember.Handlebars.compile("Another view") + }); + + aContainer.toArray(); // [aContainer.aView, aContainer.bView] + aContainer.pushObject(AnotherViewClass.create()); + aContainer.toArray(); // [aContainer.aView, aContainer.bView, ] + ``` + + Will result in the following HTML + + ```html +
    +
    A
    +
    B
    +
    Another view
    +
    + ``` + + ## Templates and Layout + + A `template`, `templateName`, `defaultTemplate`, `layout`, `layoutName` or + `defaultLayout` property on a container view will not result in the template + or layout being rendered. The HTML contents of a `Ember.ContainerView`'s DOM + representation will only be the rendered HTML of its child views. + + @class ContainerView + @namespace Ember + @extends Ember.View + */ + var ContainerView = View.extend(MutableArray, { + _states: states, + + willWatchProperty: function(prop){ + Ember.deprecate( + "ContainerViews should not be observed as arrays. This behavior will change in future implementations of ContainerView.", + !prop.match(/\[]/) && prop.indexOf('@') !== 0 + ); + }, + + init: function() { + this._super(); + + var childViews = get(this, 'childViews'); + + // redefine view's childViews property that was obliterated + defineProperty(this, 'childViews', View.childViewsProperty); + + var _childViews = this._childViews; + + forEach(childViews, function(viewName, idx) { + var view; + + if ('string' === typeof viewName) { + view = get(this, viewName); + view = this.createChildView(view); + set(this, viewName, view); + } else { + view = this.createChildView(viewName); + } + + _childViews[idx] = view; + }, this); + + var currentView = get(this, 'currentView'); + if (currentView) { + if (!_childViews.length) { _childViews = this._childViews = this._childViews.slice(); } + _childViews.push(this.createChildView(currentView)); + } + }, + + replace: function(idx, removedCount, addedViews) { + var addedCount = addedViews ? get(addedViews, 'length') : 0; + var self = this; + Ember.assert("You can't add a child to a container - the child is already a child of another view", emberA(addedViews).every(function(item) { return !get(item, '_parentView') || get(item, '_parentView') === self; })); + + this.arrayContentWillChange(idx, removedCount, addedCount); + this.childViewsWillChange(this._childViews, idx, removedCount); + + if (addedCount === 0) { + this._childViews.splice(idx, removedCount) ; + } else { + var args = [idx, removedCount].concat(addedViews); + if (addedViews.length && !this._childViews.length) { this._childViews = this._childViews.slice(); } + this._childViews.splice.apply(this._childViews, args); + } + + this.arrayContentDidChange(idx, removedCount, addedCount); + this.childViewsDidChange(this._childViews, idx, removedCount, addedCount); + + return this; + }, + + objectAt: function(idx) { + return this._childViews[idx]; + }, + + length: computed(function () { + return this._childViews.length; + })["volatile"](), + + /** + Instructs each child view to render to the passed render buffer. + + @private + @method render + @param {Ember.RenderBuffer} buffer the buffer to render to + */ + render: function(buffer) { + this.forEachChildView(function(view) { + view.renderToBuffer(buffer); + }); + }, + + instrumentName: 'container', + + /** + When a child view is removed, destroy its element so that + it is removed from the DOM. + + The array observer that triggers this action is set up in the + `renderToBuffer` method. + + @private + @method childViewsWillChange + @param {Ember.Array} views the child views array before mutation + @param {Number} start the start position of the mutation + @param {Number} removed the number of child views removed + **/ + childViewsWillChange: function(views, start, removed) { + this.propertyWillChange('childViews'); + + if (removed > 0) { + var changedViews = views.slice(start, start+removed); + // transition to preRender before clearing parentView + this.currentState.childViewsWillChange(this, views, start, removed); + this.initializeViews(changedViews, null, null); + } + }, + + removeChild: function(child) { + this.removeObject(child); + return this; + }, + + /** + When a child view is added, make sure the DOM gets updated appropriately. + + If the view has already rendered an element, we tell the child view to + create an element and insert it into the DOM. If the enclosing container + view has already written to a buffer, but not yet converted that buffer + into an element, we insert the string representation of the child into the + appropriate place in the buffer. + + @private + @method childViewsDidChange + @param {Ember.Array} views the array of child views after the mutation has occurred + @param {Number} start the start position of the mutation + @param {Number} removed the number of child views removed + @param {Number} added the number of child views added + */ + childViewsDidChange: function(views, start, removed, added) { + if (added > 0) { + var changedViews = views.slice(start, start+added); + this.initializeViews(changedViews, this, get(this, 'templateData')); + this.currentState.childViewsDidChange(this, views, start, added); + } + this.propertyDidChange('childViews'); + }, + + initializeViews: function(views, parentView, templateData) { + forEach(views, function(view) { + set(view, '_parentView', parentView); + + if (!view.container && parentView) { + set(view, 'container', parentView.container); + } + + if (!get(view, 'templateData')) { + set(view, 'templateData', templateData); + } + }); + }, + + currentView: null, + + _currentViewWillChange: beforeObserver('currentView', function() { + var currentView = get(this, 'currentView'); + if (currentView) { + currentView.destroy(); + } + }), + + _currentViewDidChange: observer('currentView', function() { + var currentView = get(this, 'currentView'); + if (currentView) { + Ember.assert("You tried to set a current view that already has a parent. Make sure you don't have multiple outlets in the same view.", !get(currentView, '_parentView')); + this.pushObject(currentView); + } + }), + + _ensureChildrenAreInDOM: function () { + this.currentState.ensureChildrenAreInDOM(this); + } + }); + + merge(states._default, { + childViewsWillChange: Ember.K, + childViewsDidChange: Ember.K, + ensureChildrenAreInDOM: Ember.K + }); + + merge(states.inBuffer, { + childViewsDidChange: function(parentView, views, start, added) { + throw new EmberError('You cannot modify child views while in the inBuffer state'); + } + }); + + merge(states.hasElement, { + childViewsWillChange: function(view, views, start, removed) { + for (var i=start; i + ``` + + ## HTML `class` Attribute + + The HTML `class` attribute of a view's tag can be set by providing a + `classNames` property that is set to an array of strings: + + ```javascript + MyView = Ember.View.extend({ + classNames: ['my-class', 'my-other-class'] + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html +
    + ``` + + `class` attribute values can also be set by providing a `classNameBindings` + property set to an array of properties names for the view. The return value + of these properties will be added as part of the value for the view's `class` + attribute. These properties can be computed properties: + + ```javascript + MyView = Ember.View.extend({ + classNameBindings: ['propertyA', 'propertyB'], + propertyA: 'from-a', + propertyB: function() { + if (someLogic) { return 'from-b'; } + }.property() + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html +
    + ``` + + If the value of a class name binding returns a boolean the property name + itself will be used as the class name if the property is true. The class name + will not be added if the value is `false` or `undefined`. + + ```javascript + MyView = Ember.View.extend({ + classNameBindings: ['hovered'], + hovered: true + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html +
    + ``` + + When using boolean class name bindings you can supply a string value other + than the property name for use as the `class` HTML attribute by appending the + preferred value after a ":" character when defining the binding: + + ```javascript + MyView = Ember.View.extend({ + classNameBindings: ['awesome:so-very-cool'], + awesome: true + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html +
    + ``` + + Boolean value class name bindings whose property names are in a + camelCase-style format will be converted to a dasherized format: + + ```javascript + MyView = Ember.View.extend({ + classNameBindings: ['isUrgent'], + isUrgent: true + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html +
    + ``` + + Class name bindings can also refer to object values that are found by + traversing a path relative to the view itself: + + ```javascript + MyView = Ember.View.extend({ + classNameBindings: ['messages.empty'] + messages: Ember.Object.create({ + empty: true + }) + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html +
    + ``` + + If you want to add a class name for a property which evaluates to true and + and a different class name if it evaluates to false, you can pass a binding + like this: + + ```javascript + // Applies 'enabled' class when isEnabled is true and 'disabled' when isEnabled is false + Ember.View.extend({ + classNameBindings: ['isEnabled:enabled:disabled'] + isEnabled: true + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html +
    + ``` + + When isEnabled is `false`, the resulting HTML reprensentation looks like + this: + + ```html +
    + ``` + + This syntax offers the convenience to add a class if a property is `false`: + + ```javascript + // Applies no class when isEnabled is true and class 'disabled' when isEnabled is false + Ember.View.extend({ + classNameBindings: ['isEnabled::disabled'] + isEnabled: true + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html +
    + ``` + + When the `isEnabled` property on the view is set to `false`, it will result + in view instances with an HTML representation of: + + ```html +
    + ``` + + Updates to the the value of a class name binding will result in automatic + update of the HTML `class` attribute in the view's rendered HTML + representation. If the value becomes `false` or `undefined` the class name + will be removed. + + Both `classNames` and `classNameBindings` are concatenated properties. See + [Ember.Object](/api/classes/Ember.Object.html) documentation for more + information about concatenated properties. + + ## HTML Attributes + + The HTML attribute section of a view's tag can be set by providing an + `attributeBindings` property set to an array of property names on the view. + The return value of these properties will be used as the value of the view's + HTML associated attribute: + + ```javascript + AnchorView = Ember.View.extend({ + tagName: 'a', + attributeBindings: ['href'], + href: 'http://google.com' + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html + + ``` + + One property can be mapped on to another by placing a ":" between + the source property and the destination property: + + ```javascript + AnchorView = Ember.View.extend({ + tagName: 'a', + attributeBindings: ['url:href'], + url: 'http://google.com' + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html + + ``` + + If the return value of an `attributeBindings` monitored property is a boolean + the property will follow HTML's pattern of repeating the attribute's name as + its value: + + ```javascript + MyTextInput = Ember.View.extend({ + tagName: 'input', + attributeBindings: ['disabled'], + disabled: true + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html + + ``` + + `attributeBindings` can refer to computed properties: + + ```javascript + MyTextInput = Ember.View.extend({ + tagName: 'input', + attributeBindings: ['disabled'], + disabled: function() { + if (someLogic) { + return true; + } else { + return false; + } + }.property() + }); + ``` + + Updates to the the property of an attribute binding will result in automatic + update of the HTML attribute in the view's rendered HTML representation. + + `attributeBindings` is a concatenated property. See [Ember.Object](/api/classes/Ember.Object.html) + documentation for more information about concatenated properties. + + ## Templates + + The HTML contents of a view's rendered representation are determined by its + template. Templates can be any function that accepts an optional context + parameter and returns a string of HTML that will be inserted within the + view's tag. Most typically in Ember this function will be a compiled + `Ember.Handlebars` template. + + ```javascript + AView = Ember.View.extend({ + template: Ember.Handlebars.compile('I am the template') + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html +
    I am the template
    + ``` + + Within an Ember application is more common to define a Handlebars templates as + part of a page: + + ```html + + ``` + + And associate it by name using a view's `templateName` property: + + ```javascript + AView = Ember.View.extend({ + templateName: 'some-template' + }); + ``` + + If you have nested resources, your Handlebars template will look like this: + + ```html + + ``` + + And `templateName` property: + + ```javascript + AView = Ember.View.extend({ + templateName: 'posts/new' + }); + ``` + + Using a value for `templateName` that does not have a Handlebars template + with a matching `data-template-name` attribute will throw an error. + + For views classes that may have a template later defined (e.g. as the block + portion of a `{{view}}` Handlebars helper call in another template or in + a subclass), you can provide a `defaultTemplate` property set to compiled + template function. If a template is not later provided for the view instance + the `defaultTemplate` value will be used: + + ```javascript + AView = Ember.View.extend({ + defaultTemplate: Ember.Handlebars.compile('I was the default'), + template: null, + templateName: null + }); + ``` + + Will result in instances with an HTML representation of: + + ```html +
    I was the default
    + ``` + + If a `template` or `templateName` is provided it will take precedence over + `defaultTemplate`: + + ```javascript + AView = Ember.View.extend({ + defaultTemplate: Ember.Handlebars.compile('I was the default') + }); + + aView = AView.create({ + template: Ember.Handlebars.compile('I was the template, not default') + }); + ``` + + Will result in the following HTML representation when rendered: + + ```html +
    I was the template, not default
    + ``` + + ## View Context + + The default context of the compiled template is the view's controller: + + ```javascript + AView = Ember.View.extend({ + template: Ember.Handlebars.compile('Hello {{excitedGreeting}}') + }); + + aController = Ember.Object.create({ + firstName: 'Barry', + excitedGreeting: function() { + return this.get("content.firstName") + "!!!" + }.property() + }); + + aView = AView.create({ + controller: aController + }); + ``` + + Will result in an HTML representation of: + + ```html +
    Hello Barry!!!
    + ``` + + A context can also be explicitly supplied through the view's `context` + property. If the view has neither `context` nor `controller` properties, the + `parentView`'s context will be used. + + ## Layouts + + Views can have a secondary template that wraps their main template. Like + primary templates, layouts can be any function that accepts an optional + context parameter and returns a string of HTML that will be inserted inside + view's tag. Views whose HTML element is self closing (e.g. ``) + cannot have a layout and this property will be ignored. + + Most typically in Ember a layout will be a compiled `Ember.Handlebars` + template. + + A view's layout can be set directly with the `layout` property or reference + an existing Handlebars template by name with the `layoutName` property. + + A template used as a layout must contain a single use of the Handlebars + `{{yield}}` helper. The HTML contents of a view's rendered `template` will be + inserted at this location: + + ```javascript + AViewWithLayout = Ember.View.extend({ + layout: Ember.Handlebars.compile("
    {{yield}}
    "), + template: Ember.Handlebars.compile("I got wrapped") + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html +
    +
    + I got wrapped +
    +
    + ``` + + See [Ember.Handlebars.helpers.yield](/api/classes/Ember.Handlebars.helpers.html#method_yield) + for more information. + + ## Responding to Browser Events + + Views can respond to user-initiated events in one of three ways: method + implementation, through an event manager, and through `{{action}}` helper use + in their template or layout. + + ### Method Implementation + + Views can respond to user-initiated events by implementing a method that + matches the event name. A `jQuery.Event` object will be passed as the + argument to this method. + + ```javascript + AView = Ember.View.extend({ + click: function(event) { + // will be called when when an instance's + // rendered element is clicked + } + }); + ``` + + ### Event Managers + + Views can define an object as their `eventManager` property. This object can + then implement methods that match the desired event names. Matching events + that occur on the view's rendered HTML or the rendered HTML of any of its DOM + descendants will trigger this method. A `jQuery.Event` object will be passed + as the first argument to the method and an `Ember.View` object as the + second. The `Ember.View` will be the view whose rendered HTML was interacted + with. This may be the view with the `eventManager` property or one of its + descendent views. + + ```javascript + AView = Ember.View.extend({ + eventManager: Ember.Object.create({ + doubleClick: function(event, view) { + // will be called when when an instance's + // rendered element or any rendering + // of this views's descendent + // elements is clicked + } + }) + }); + ``` + + An event defined for an event manager takes precedence over events of the + same name handled through methods on the view. + + ```javascript + AView = Ember.View.extend({ + mouseEnter: function(event) { + // will never trigger. + }, + eventManager: Ember.Object.create({ + mouseEnter: function(event, view) { + // takes precedence over AView#mouseEnter + } + }) + }); + ``` + + Similarly a view's event manager will take precedence for events of any views + rendered as a descendent. A method name that matches an event name will not + be called if the view instance was rendered inside the HTML representation of + a view that has an `eventManager` property defined that handles events of the + name. Events not handled by the event manager will still trigger method calls + on the descendent. + + ```javascript + OuterView = Ember.View.extend({ + template: Ember.Handlebars.compile("outer {{#view InnerView}}inner{{/view}} outer"), + eventManager: Ember.Object.create({ + mouseEnter: function(event, view) { + // view might be instance of either + // OuterView or InnerView depending on + // where on the page the user interaction occured + } + }) + }); + + InnerView = Ember.View.extend({ + click: function(event) { + // will be called if rendered inside + // an OuterView because OuterView's + // eventManager doesn't handle click events + }, + mouseEnter: function(event) { + // will never be called if rendered inside + // an OuterView. + } + }); + ``` + + ### Handlebars `{{action}}` Helper + + See [Handlebars.helpers.action](/api/classes/Ember.Handlebars.helpers.html#method_action). + + ### Event Names + + All of the event handling approaches described above respond to the same set + of events. The names of the built-in events are listed below. (The hash of + built-in events exists in `Ember.EventDispatcher`.) Additional, custom events + can be registered by using `Ember.Application.customEvents`. + + Touch events: + + * `touchStart` + * `touchMove` + * `touchEnd` + * `touchCancel` + + Keyboard events + + * `keyDown` + * `keyUp` + * `keyPress` + + Mouse events + + * `mouseDown` + * `mouseUp` + * `contextMenu` + * `click` + * `doubleClick` + * `mouseMove` + * `focusIn` + * `focusOut` + * `mouseEnter` + * `mouseLeave` + + Form events: + + * `submit` + * `change` + * `focusIn` + * `focusOut` + * `input` + + HTML5 drag and drop events: + + * `dragStart` + * `drag` + * `dragEnter` + * `dragLeave` + * `dragOver` + * `dragEnd` + * `drop` + + ## Handlebars `{{view}}` Helper + + Other `Ember.View` instances can be included as part of a view's template by + using the `{{view}}` Handlebars helper. See [Ember.Handlebars.helpers.view](/api/classes/Ember.Handlebars.helpers.html#method_view) + for additional information. + + @class View + @namespace Ember + @extends Ember.CoreView + */ + var View = CoreView.extend({ + + concatenatedProperties: ['classNames', 'classNameBindings', 'attributeBindings'], + + /** + @property isView + @type Boolean + @default true + @static + */ + isView: true, + + // .......................................................... + // TEMPLATE SUPPORT + // + + /** + The name of the template to lookup if no template is provided. + + By default `Ember.View` will lookup a template with this name in + `Ember.TEMPLATES` (a shared global object). + + @property templateName + @type String + @default null + */ + templateName: null, + + /** + The name of the layout to lookup if no layout is provided. + + By default `Ember.View` will lookup a template with this name in + `Ember.TEMPLATES` (a shared global object). + + @property layoutName + @type String + @default null + */ + layoutName: null, + + /** + Used to identify this view during debugging + + @property instrumentDisplay + @type String + */ + instrumentDisplay: computed(function() { + if (this.helperName) { + return '{{' + this.helperName + '}}'; + } + }), + + /** + The template used to render the view. This should be a function that + accepts an optional context parameter and returns a string of HTML that + will be inserted into the DOM relative to its parent view. + + In general, you should set the `templateName` property instead of setting + the template yourself. + + @property template + @type Function + */ + template: computed('templateName', function(key, value) { + if (value !== undefined) { return value; } + + var templateName = get(this, 'templateName'), + template = this.templateForName(templateName, 'template'); + + Ember.assert("You specified the templateName " + templateName + " for " + this + ", but it did not exist.", !templateName || template); + + return template || get(this, 'defaultTemplate'); + }), + + /** + The controller managing this view. If this property is set, it will be + made available for use by the template. + + @property controller + @type Object + */ + controller: computed('_parentView', function(key) { + var parentView = get(this, '_parentView'); + return parentView ? get(parentView, 'controller') : null; + }), + + /** + A view may contain a layout. A layout is a regular template but + supersedes the `template` property during rendering. It is the + responsibility of the layout template to retrieve the `template` + property from the view (or alternatively, call `Handlebars.helpers.yield`, + `{{yield}}`) to render it in the correct location. + + This is useful for a view that has a shared wrapper, but which delegates + the rendering of the contents of the wrapper to the `template` property + on a subclass. + + @property layout + @type Function + */ + layout: computed(function(key) { + var layoutName = get(this, 'layoutName'), + layout = this.templateForName(layoutName, 'layout'); + + Ember.assert("You specified the layoutName " + layoutName + " for " + this + ", but it did not exist.", !layoutName || layout); + + return layout || get(this, 'defaultLayout'); + }).property('layoutName'), + + _yield: function(context, options) { + var template = get(this, 'template'); + if (template) { template(context, options); } + }, + + templateForName: function(name, type) { + if (!name) { return; } + Ember.assert("templateNames are not allowed to contain periods: "+name, name.indexOf('.') === -1); + + if (!this.container) { + throw new EmberError('Container was not found when looking up a views template. ' + + 'This is most likely due to manually instantiating an Ember.View. ' + + 'See: http://git.io/EKPpnA'); + } + + return this.container.lookup('template:' + name); + }, + + /** + The object from which templates should access properties. + + This object will be passed to the template function each time the render + method is called, but it is up to the individual function to decide what + to do with it. + + By default, this will be the view's controller. + + @property context + @type Object + */ + context: computed(function(key, value) { + if (arguments.length === 2) { + set(this, '_context', value); + return value; + } else { + return get(this, '_context'); + } + })["volatile"](), + + /** + Private copy of the view's template context. This can be set directly + by Handlebars without triggering the observer that causes the view + to be re-rendered. + + The context of a view is looked up as follows: + + 1. Supplied context (usually by Handlebars) + 2. Specified controller + 3. `parentView`'s context (for a child of a ContainerView) + + The code in Handlebars that overrides the `_context` property first + checks to see whether the view has a specified controller. This is + something of a hack and should be revisited. + + @property _context + @private + */ + _context: computed(function(key) { + var parentView, controller; + + if (controller = get(this, 'controller')) { + return controller; + } + + parentView = this._parentView; + if (parentView) { + return get(parentView, '_context'); + } + + return null; + }), + + /** + If a value that affects template rendering changes, the view should be + re-rendered to reflect the new value. + + @method _contextDidChange + @private + */ + _contextDidChange: observer('context', function() { + this.rerender(); + }), + + /** + If `false`, the view will appear hidden in DOM. + + @property isVisible + @type Boolean + @default null + */ + isVisible: true, + + /** + Array of child views. You should never edit this array directly. + Instead, use `appendChild` and `removeFromParent`. + + @property childViews + @type Array + @default [] + @private + */ + childViews: childViewsProperty, + + _childViews: EMPTY_ARRAY, + + // When it's a virtual view, we need to notify the parent that their + // childViews will change. + _childViewsWillChange: beforeObserver('childViews', function() { + if (this.isVirtual) { + var parentView = get(this, 'parentView'); + if (parentView) { propertyWillChange(parentView, 'childViews'); } + } + }), + + // When it's a virtual view, we need to notify the parent that their + // childViews did change. + _childViewsDidChange: observer('childViews', function() { + if (this.isVirtual) { + var parentView = get(this, 'parentView'); + if (parentView) { propertyDidChange(parentView, 'childViews'); } + } + }), + + /** + Return the nearest ancestor that is an instance of the provided + class. + + @method nearestInstanceOf + @param {Class} klass Subclass of Ember.View (or Ember.View itself) + @return Ember.View + @deprecated + */ + nearestInstanceOf: function(klass) { + Ember.deprecate("nearestInstanceOf is deprecated and will be removed from future releases. Use nearestOfType."); + var view = get(this, 'parentView'); + + while (view) { + if (view instanceof klass) { return view; } + view = get(view, 'parentView'); + } + }, + + /** + Return the nearest ancestor that is an instance of the provided + class or mixin. + + @method nearestOfType + @param {Class,Mixin} klass Subclass of Ember.View (or Ember.View itself), + or an instance of Ember.Mixin. + @return Ember.View + */ + nearestOfType: function(klass) { + var view = get(this, 'parentView'), + isOfType = klass instanceof Mixin ? + function(view) { return klass.detect(view); } : + function(view) { return klass.detect(view.constructor); }; + + while (view) { + if (isOfType(view)) { return view; } + view = get(view, 'parentView'); + } + }, + + /** + Return the nearest ancestor that has a given property. + + @method nearestWithProperty + @param {String} property A property name + @return Ember.View + */ + nearestWithProperty: function(property) { + var view = get(this, 'parentView'); + + while (view) { + if (property in view) { return view; } + view = get(view, 'parentView'); + } + }, + + /** + Return the nearest ancestor whose parent is an instance of + `klass`. + + @method nearestChildOf + @param {Class} klass Subclass of Ember.View (or Ember.View itself) + @return Ember.View + */ + nearestChildOf: function(klass) { + var view = get(this, 'parentView'); + + while (view) { + if (get(view, 'parentView') instanceof klass) { return view; } + view = get(view, 'parentView'); + } + }, + + /** + When the parent view changes, recursively invalidate `controller` + + @method _parentViewDidChange + @private + */ + _parentViewDidChange: observer('_parentView', function() { + if (this.isDestroying) { return; } + + this.trigger('parentViewDidChange'); + + if (get(this, 'parentView.controller') && !get(this, 'controller')) { + this.notifyPropertyChange('controller'); + } + }), + + _controllerDidChange: observer('controller', function() { + if (this.isDestroying) { return; } + + this.rerender(); + + this.forEachChildView(function(view) { + view.propertyDidChange('controller'); + }); + }), + + cloneKeywords: function() { + var templateData = get(this, 'templateData'); + + var keywords = templateData ? copy(templateData.keywords) : {}; + set(keywords, 'view', this.isVirtual ? keywords.view : this); + set(keywords, '_view', this); + set(keywords, 'controller', get(this, 'controller')); + + return keywords; + }, + + /** + Called on your view when it should push strings of HTML into a + `Ember.RenderBuffer`. Most users will want to override the `template` + or `templateName` properties instead of this method. + + By default, `Ember.View` will look for a function in the `template` + property and invoke it with the value of `context`. The value of + `context` will be the view's controller unless you override it. + + @method render + @param {Ember.RenderBuffer} buffer The render buffer + */ + render: function(buffer) { + // If this view has a layout, it is the responsibility of the + // the layout to render the view's template. Otherwise, render the template + // directly. + var template = get(this, 'layout') || get(this, 'template'); + + if (template) { + var context = get(this, 'context'); + var keywords = this.cloneKeywords(); + var output; + + var data = { + view: this, + buffer: buffer, + isRenderData: true, + keywords: keywords, + insideGroup: get(this, 'templateData.insideGroup') + }; + + // Invoke the template with the provided template context, which + // is the view's controller by default. A hash of data is also passed that provides + // the template with access to the view and render buffer. + + Ember.assert('template must be a function. Did you mean to call Ember.Handlebars.compile("...") or specify templateName instead?', typeof template === 'function'); + // The template should write directly to the render buffer instead + // of returning a string. + output = template(context, { data: data }); + + // If the template returned a string instead of writing to the buffer, + // push the string onto the buffer. + if (output !== undefined) { buffer.push(output); } + } + }, + + /** + Renders the view again. This will work regardless of whether the + view is already in the DOM or not. If the view is in the DOM, the + rendering process will be deferred to give bindings a chance + to synchronize. + + If children were added during the rendering process using `appendChild`, + `rerender` will remove them, because they will be added again + if needed by the next `render`. + + In general, if the display of your view changes, you should modify + the DOM element directly instead of manually calling `rerender`, which can + be slow. + + @method rerender + */ + rerender: function() { + return this.currentState.rerender(this); + }, + + clearRenderedChildren: function() { + var lengthBefore = this.lengthBeforeRender, + lengthAfter = this.lengthAfterRender; + + // If there were child views created during the last call to render(), + // remove them under the assumption that they will be re-created when + // we re-render. + + // VIEW-TODO: Unit test this path. + var childViews = this._childViews; + for (var i=lengthAfter-1; i>=lengthBefore; i--) { + if (childViews[i]) { childViews[i].destroy(); } + } + }, + + /** + Iterates over the view's `classNameBindings` array, inserts the value + of the specified property into the `classNames` array, then creates an + observer to update the view's element if the bound property ever changes + in the future. + + @method _applyClassNameBindings + @private + */ + _applyClassNameBindings: function(classBindings) { + var classNames = this.classNames, + elem, newClass, dasherizedClass; + + // Loop through all of the configured bindings. These will be either + // property names ('isUrgent') or property paths relative to the view + // ('content.isUrgent') + forEach(classBindings, function(binding) { + + Ember.assert("classNameBindings must not have spaces in them. Multiple class name bindings can be provided as elements of an array, e.g. ['foo', ':bar']", binding.indexOf(' ') === -1); + + // Variable in which the old class value is saved. The observer function + // closes over this variable, so it knows which string to remove when + // the property changes. + var oldClass; + // Extract just the property name from bindings like 'foo:bar' + var parsedPath = View._parsePropertyPath(binding); + + // Set up an observer on the context. If the property changes, toggle the + // class name. + var observer = function() { + // Get the current value of the property + newClass = this._classStringForProperty(binding); + elem = this.$(); + + // If we had previously added a class to the element, remove it. + if (oldClass) { + elem.removeClass(oldClass); + // Also remove from classNames so that if the view gets rerendered, + // the class doesn't get added back to the DOM. + classNames.removeObject(oldClass); + } + + // If necessary, add a new class. Make sure we keep track of it so + // it can be removed in the future. + if (newClass) { + elem.addClass(newClass); + oldClass = newClass; + } else { + oldClass = null; + } + }; + + // Get the class name for the property at its current value + dasherizedClass = this._classStringForProperty(binding); + + if (dasherizedClass) { + // Ensure that it gets into the classNames array + // so it is displayed when we render. + addObject(classNames, dasherizedClass); + + // Save a reference to the class name so we can remove it + // if the observer fires. Remember that this variable has + // been closed over by the observer. + oldClass = dasherizedClass; + } + + this.registerObserver(this, parsedPath.path, observer); + // Remove className so when the view is rerendered, + // the className is added based on binding reevaluation + this.one('willClearRender', function() { + if (oldClass) { + classNames.removeObject(oldClass); + oldClass = null; + } + }); + + }, this); + }, + + _unspecifiedAttributeBindings: null, + + /** + Iterates through the view's attribute bindings, sets up observers for each, + then applies the current value of the attributes to the passed render buffer. + + @method _applyAttributeBindings + @param {Ember.RenderBuffer} buffer + @private + */ + _applyAttributeBindings: function(buffer, attributeBindings) { + var attributeValue, + unspecifiedAttributeBindings = this._unspecifiedAttributeBindings = this._unspecifiedAttributeBindings || {}; + + forEach(attributeBindings, function(binding) { + var split = binding.split(':'), + property = split[0], + attributeName = split[1] || property; + + if (property in this) { + this._setupAttributeBindingObservation(property, attributeName); + + // Determine the current value and add it to the render buffer + // if necessary. + attributeValue = get(this, property); + View.applyAttributeBindings(buffer, attributeName, attributeValue); + } else { + unspecifiedAttributeBindings[property] = attributeName; + } + }, this); + + // Lazily setup setUnknownProperty after attributeBindings are initially applied + this.setUnknownProperty = this._setUnknownProperty; + }, + + _setupAttributeBindingObservation: function(property, attributeName) { + var attributeValue, elem; + + // Create an observer to add/remove/change the attribute if the + // JavaScript property changes. + var observer = function() { + elem = this.$(); + + attributeValue = get(this, property); + + View.applyAttributeBindings(elem, attributeName, attributeValue); + }; + + this.registerObserver(this, property, observer); + }, + + /** + We're using setUnknownProperty as a hook to setup attributeBinding observers for + properties that aren't defined on a view at initialization time. + + Note: setUnknownProperty will only be called once for each property. + + @method setUnknownProperty + @param key + @param value + @private + */ + setUnknownProperty: null, // Gets defined after initialization by _applyAttributeBindings + + _setUnknownProperty: function(key, value) { + var attributeName = this._unspecifiedAttributeBindings && this._unspecifiedAttributeBindings[key]; + if (attributeName) { + this._setupAttributeBindingObservation(key, attributeName); + } + + defineProperty(this, key); + return set(this, key, value); + }, + + /** + Given a property name, returns a dasherized version of that + property name if the property evaluates to a non-falsy value. + + For example, if the view has property `isUrgent` that evaluates to true, + passing `isUrgent` to this method will return `"is-urgent"`. + + @method _classStringForProperty + @param property + @private + */ + _classStringForProperty: function(property) { + var parsedPath = View._parsePropertyPath(property); + var path = parsedPath.path; + + var val = get(this, path); + if (val === undefined && isGlobalPath(path)) { + val = get(Ember.lookup, path); + } + + return View._classStringForValue(path, val, parsedPath.className, parsedPath.falsyClassName); + }, + + // .......................................................... + // ELEMENT SUPPORT + // + + /** + Returns the current DOM element for the view. + + @property element + @type DOMElement + */ + element: computed('_parentView', function(key, value) { + if (value !== undefined) { + return this.currentState.setElement(this, value); + } else { + return this.currentState.getElement(this); + } + }), + + /** + Returns a jQuery object for this view's element. If you pass in a selector + string, this method will return a jQuery object, using the current element + as its buffer. + + For example, calling `view.$('li')` will return a jQuery object containing + all of the `li` elements inside the DOM element of this view. + + @method $ + @param {String} [selector] a jQuery-compatible selector string + @return {jQuery} the jQuery object for the DOM node + */ + $: function(sel) { + return this.currentState.$(this, sel); + }, + + mutateChildViews: function(callback) { + var childViews = this._childViews, + idx = childViews.length, + view; + + while(--idx >= 0) { + view = childViews[idx]; + callback(this, view, idx); + } + + return this; + }, + + forEachChildView: function(callback) { + var childViews = this._childViews; + + if (!childViews) { return this; } + + var len = childViews.length, + view, idx; + + for (idx = 0; idx < len; idx++) { + view = childViews[idx]; + callback(view); + } + + return this; + }, + + /** + Appends the view's element to the specified parent element. + + If the view does not have an HTML representation yet, `createElement()` + will be called automatically. + + Note that this method just schedules the view to be appended; the DOM + element will not be appended to the given element until all bindings have + finished synchronizing. + + This is not typically a function that you will need to call directly when + building your application. You might consider using `Ember.ContainerView` + instead. If you do need to use `appendTo`, be sure that the target element + you are providing is associated with an `Ember.Application` and does not + have an ancestor element that is associated with an Ember view. + + @method appendTo + @param {String|DOMElement|jQuery} A selector, element, HTML string, or jQuery object + @return {Ember.View} receiver + */ + appendTo: function(target) { + // Schedule the DOM element to be created and appended to the given + // element after bindings have synchronized. + this._insertElementLater(function() { + Ember.assert("You tried to append to (" + target + ") but that isn't in the DOM", jQuery(target).length > 0); + Ember.assert("You cannot append to an existing Ember.View. Consider using Ember.ContainerView instead.", !jQuery(target).is('.ember-view') && !jQuery(target).parents().is('.ember-view')); + this.$().appendTo(target); + }); + + return this; + }, + + /** + Replaces the content of the specified parent element with this view's + element. If the view does not have an HTML representation yet, + `createElement()` will be called automatically. + + Note that this method just schedules the view to be appended; the DOM + element will not be appended to the given element until all bindings have + finished synchronizing + + @method replaceIn + @param {String|DOMElement|jQuery} target A selector, element, HTML string, or jQuery object + @return {Ember.View} received + */ + replaceIn: function(target) { + Ember.assert("You tried to replace in (" + target + ") but that isn't in the DOM", jQuery(target).length > 0); + Ember.assert("You cannot replace an existing Ember.View. Consider using Ember.ContainerView instead.", !jQuery(target).is('.ember-view') && !jQuery(target).parents().is('.ember-view')); + + this._insertElementLater(function() { + jQuery(target).empty(); + this.$().appendTo(target); + }); + + return this; + }, + + /** + Schedules a DOM operation to occur during the next render phase. This + ensures that all bindings have finished synchronizing before the view is + rendered. + + To use, pass a function that performs a DOM operation. + + Before your function is called, this view and all child views will receive + the `willInsertElement` event. After your function is invoked, this view + and all of its child views will receive the `didInsertElement` event. + + ```javascript + view._insertElementLater(function() { + this.createElement(); + this.$().appendTo('body'); + }); + ``` + + @method _insertElementLater + @param {Function} fn the function that inserts the element into the DOM + @private + */ + _insertElementLater: function(fn) { + this._scheduledInsert = run.scheduleOnce('render', this, '_insertElement', fn); + }, + + _insertElement: function (fn) { + this._scheduledInsert = null; + this.currentState.insertElement(this, fn); + }, + + /** + Appends the view's element to the document body. If the view does + not have an HTML representation yet, `createElement()` will be called + automatically. + + If your application uses the `rootElement` property, you must append + the view within that element. Rendering views outside of the `rootElement` + is not supported. + + Note that this method just schedules the view to be appended; the DOM + element will not be appended to the document body until all bindings have + finished synchronizing. + + @method append + @return {Ember.View} receiver + */ + append: function() { + return this.appendTo(document.body); + }, + + /** + Removes the view's element from the element to which it is attached. + + @method remove + @return {Ember.View} receiver + */ + remove: function() { + // What we should really do here is wait until the end of the run loop + // to determine if the element has been re-appended to a different + // element. + // In the interim, we will just re-render if that happens. It is more + // important than elements get garbage collected. + if (!this.removedFromDOM) { this.destroyElement(); } + this.invokeRecursively(function(view) { + if (view.clearRenderedChildren) { view.clearRenderedChildren(); } + }); + }, + + elementId: null, + + /** + Attempts to discover the element in the parent element. The default + implementation looks for an element with an ID of `elementId` (or the + view's guid if `elementId` is null). You can override this method to + provide your own form of lookup. For example, if you want to discover your + element using a CSS class name instead of an ID. + + @method findElementInParentElement + @param {DOMElement} parentElement The parent's DOM element + @return {DOMElement} The discovered element + */ + findElementInParentElement: function(parentElem) { + var id = "#" + this.elementId; + return jQuery(id)[0] || jQuery(id, parentElem)[0]; + }, + + /** + Creates a DOM representation of the view and all of its + child views by recursively calling the `render()` method. + + After the element has been created, `didInsertElement` will + be called on this view and all of its child views. + + @method createElement + @return {Ember.View} receiver + */ + createElement: function() { + if (get(this, 'element')) { return this; } + + var buffer = this.renderToBuffer(); + set(this, 'element', buffer.element()); + + return this; + }, + + /** + Called when a view is going to insert an element into the DOM. + + @event willInsertElement + */ + willInsertElement: Ember.K, + + /** + Called when the element of the view has been inserted into the DOM + or after the view was re-rendered. Override this function to do any + set up that requires an element in the document body. + + @event didInsertElement + */ + didInsertElement: Ember.K, + + /** + Called when the view is about to rerender, but before anything has + been torn down. This is a good opportunity to tear down any manual + observers you have installed based on the DOM state + + @event willClearRender + */ + willClearRender: Ember.K, + + /** + Run this callback on the current view (unless includeSelf is false) and recursively on child views. + + @method invokeRecursively + @param fn {Function} + @param includeSelf {Boolean} Includes itself if true. + @private + */ + invokeRecursively: function(fn, includeSelf) { + var childViews = (includeSelf === false) ? this._childViews : [this]; + var currentViews, view, currentChildViews; + + while (childViews.length) { + currentViews = childViews.slice(); + childViews = []; + + for (var i=0, l=currentViews.length; i` tag for views. + + @property tagName + @type String + @default null + */ + + // We leave this null by default so we can tell the difference between + // the default case and a user-specified tag. + tagName: null, + + /** + The WAI-ARIA role of the control represented by this view. For example, a + button may have a role of type 'button', or a pane may have a role of + type 'alertdialog'. This property is used by assistive software to help + visually challenged users navigate rich web applications. + + The full list of valid WAI-ARIA roles is available at: + [http://www.w3.org/TR/wai-aria/roles#roles_categorization](http://www.w3.org/TR/wai-aria/roles#roles_categorization) + + @property ariaRole + @type String + @default null + */ + ariaRole: null, + + /** + Standard CSS class names to apply to the view's outer element. This + property automatically inherits any class names defined by the view's + superclasses as well. + + @property classNames + @type Array + @default ['ember-view'] + */ + classNames: ['ember-view'], + + /** + A list of properties of the view to apply as class names. If the property + is a string value, the value of that string will be applied as a class + name. + + ```javascript + // Applies the 'high' class to the view element + Ember.View.extend({ + classNameBindings: ['priority'] + priority: 'high' + }); + ``` + + If the value of the property is a Boolean, the name of that property is + added as a dasherized class name. + + ```javascript + // Applies the 'is-urgent' class to the view element + Ember.View.extend({ + classNameBindings: ['isUrgent'] + isUrgent: true + }); + ``` + + If you would prefer to use a custom value instead of the dasherized + property name, you can pass a binding like this: + + ```javascript + // Applies the 'urgent' class to the view element + Ember.View.extend({ + classNameBindings: ['isUrgent:urgent'] + isUrgent: true + }); + ``` + + This list of properties is inherited from the view's superclasses as well. + + @property classNameBindings + @type Array + @default [] + */ + classNameBindings: EMPTY_ARRAY, + + /** + A list of properties of the view to apply as attributes. If the property is + a string value, the value of that string will be applied as the attribute. + + ```javascript + // Applies the type attribute to the element + // with the value "button", like
    + Ember.View.extend({ + attributeBindings: ['type'], + type: 'button' + }); + ``` + + If the value of the property is a Boolean, the name of that property is + added as an attribute. + + ```javascript + // Renders something like
    + Ember.View.extend({ + attributeBindings: ['enabled'], + enabled: true + }); + ``` + + @property attributeBindings + */ + attributeBindings: EMPTY_ARRAY, + + // ....................................................... + // CORE DISPLAY METHODS + // + + /** + Setup a view, but do not finish waking it up. + + * configure `childViews` + * register the view with the global views hash, which is used for event + dispatch + + @method init + @private + */ + init: function() { + this.elementId = this.elementId || guidFor(this); + + this._super(); + + // setup child views. be sure to clone the child views array first + this._childViews = this._childViews.slice(); + + Ember.assert("Only arrays are allowed for 'classNameBindings'", typeOf(this.classNameBindings) === 'array'); + this.classNameBindings = emberA(this.classNameBindings.slice()); + + Ember.assert("Only arrays are allowed for 'classNames'", typeOf(this.classNames) === 'array'); + this.classNames = emberA(this.classNames.slice()); + }, + + appendChild: function(view, options) { + return this.currentState.appendChild(this, view, options); + }, + + /** + Removes the child view from the parent view. + + @method removeChild + @param {Ember.View} view + @return {Ember.View} receiver + */ + removeChild: function(view) { + // If we're destroying, the entire subtree will be + // freed, and the DOM will be handled separately, + // so no need to mess with childViews. + if (this.isDestroying) { return; } + + // update parent node + set(view, '_parentView', null); + + // remove view from childViews array. + var childViews = this._childViews; + + removeObject(childViews, view); + + this.propertyDidChange('childViews'); // HUH?! what happened to will change? + + return this; + }, + + /** + Removes all children from the `parentView`. + + @method removeAllChildren + @return {Ember.View} receiver + */ + removeAllChildren: function() { + return this.mutateChildViews(function(parentView, view) { + parentView.removeChild(view); + }); + }, + + destroyAllChildren: function() { + return this.mutateChildViews(function(parentView, view) { + view.destroy(); + }); + }, + + /** + Removes the view from its `parentView`, if one is found. Otherwise + does nothing. + + @method removeFromParent + @return {Ember.View} receiver + */ + removeFromParent: function() { + var parent = this._parentView; + + // Remove DOM element from parent + this.remove(); + + if (parent) { parent.removeChild(this); } + return this; + }, + + /** + You must call `destroy` on a view to destroy the view (and all of its + child views). This will remove the view from any parent node, then make + sure that the DOM element managed by the view can be released by the + memory manager. + + @method destroy + */ + destroy: function() { + var childViews = this._childViews, + // get parentView before calling super because it'll be destroyed + nonVirtualParentView = get(this, 'parentView'), + viewName = this.viewName, + childLen, i; + + if (!this._super()) { return; } + + childLen = childViews.length; + for (i=childLen-1; i>=0; i--) { + childViews[i].removedFromDOM = true; + } + + // remove from non-virtual parent view if viewName was specified + if (viewName && nonVirtualParentView) { + nonVirtualParentView.set(viewName, null); + } + + childLen = childViews.length; + for (i=childLen-1; i>=0; i--) { + childViews[i].destroy(); + } + + return this; + }, + + /** + Instantiates a view to be added to the childViews array during view + initialization. You generally will not call this method directly unless + you are overriding `createChildViews()`. Note that this method will + automatically configure the correct settings on the new view instance to + act as a child of the parent. + + @method createChildView + @param {Class|String} viewClass + @param {Hash} [attrs] Attributes to add + @return {Ember.View} new instance + */ + createChildView: function(view, attrs) { + if (!view) { + throw new TypeError("createChildViews first argument must exist"); + } + + if (view.isView && view._parentView === this && view.container === this.container) { + return view; + } + + attrs = attrs || {}; + attrs._parentView = this; + + if (CoreView.detect(view)) { + attrs.templateData = attrs.templateData || get(this, 'templateData'); + + attrs.container = this.container; + view = view.create(attrs); + + // don't set the property on a virtual view, as they are invisible to + // consumers of the view API + if (view.viewName) { + set(get(this, 'concreteView'), view.viewName, view); + } + } else if ('string' === typeof view) { + var fullName = 'view:' + view; + var ViewKlass = this.container.lookupFactory(fullName); + + Ember.assert("Could not find view: '" + fullName + "'", !!ViewKlass); + + attrs.templateData = get(this, 'templateData'); + view = ViewKlass.create(attrs); + } else { + Ember.assert('You must pass instance or subclass of View', view.isView); + attrs.container = this.container; + + if (!get(view, 'templateData')) { + attrs.templateData = get(this, 'templateData'); + } + + setProperties(view, attrs); + + } + + return view; + }, + + becameVisible: Ember.K, + becameHidden: Ember.K, + + /** + When the view's `isVisible` property changes, toggle the visibility + element of the actual DOM element. + + @method _isVisibleDidChange + @private + */ + _isVisibleDidChange: observer('isVisible', function() { + if (this._isVisible === get(this, 'isVisible')) { return ; } + run.scheduleOnce('render', this, this._toggleVisibility); + }), + + _toggleVisibility: function() { + var $el = this.$(); + if (!$el) { return; } + + var isVisible = get(this, 'isVisible'); + + if (this._isVisible === isVisible) { return ; } + + $el.toggle(isVisible); + + this._isVisible = isVisible; + + if (this._isAncestorHidden()) { return; } + + if (isVisible) { + this._notifyBecameVisible(); + } else { + this._notifyBecameHidden(); + } + }, + + _notifyBecameVisible: function() { + this.trigger('becameVisible'); + + this.forEachChildView(function(view) { + var isVisible = get(view, 'isVisible'); + + if (isVisible || isVisible === null) { + view._notifyBecameVisible(); + } + }); + }, + + _notifyBecameHidden: function() { + this.trigger('becameHidden'); + this.forEachChildView(function(view) { + var isVisible = get(view, 'isVisible'); + + if (isVisible || isVisible === null) { + view._notifyBecameHidden(); + } + }); + }, + + _isAncestorHidden: function() { + var parent = get(this, 'parentView'); + + while (parent) { + if (get(parent, 'isVisible') === false) { return true; } + + parent = get(parent, 'parentView'); + } + + return false; + }, + + clearBuffer: function() { + this.invokeRecursively(nullViewsBuffer); + }, + transitionTo: function(state, children) { + Ember.deprecate("Ember.View#transitionTo has been deprecated, it is for internal use only"); + this._transitionTo(state, children); + }, + _transitionTo: function(state, children) { + var priorState = this.currentState; + var currentState = this.currentState = this._states[state]; + + this._state = state; + + if (priorState && priorState.exit) { priorState.exit(this); } + if (currentState.enter) { currentState.enter(this); } + if (state === 'inDOM') { meta(this).cache.element = undefined; } + + if (children !== false) { + this.forEachChildView(function(view) { + view._transitionTo(state); + }); + } + }, + + // ....................................................... + // EVENT HANDLING + // + + /** + Handle events from `Ember.EventDispatcher` + + @method handleEvent + @param eventName {String} + @param evt {Event} + @private + */ + handleEvent: function(eventName, evt) { + return this.currentState.handleEvent(this, eventName, evt); + }, + + registerObserver: function(root, path, target, observer) { + if (!observer && 'function' === typeof target) { + observer = target; + target = null; + } + + if (!root || typeof root !== 'object') { + return; + } + + var view = this, + stateCheckedObserver = function() { + view.currentState.invokeObserver(this, observer); + }, + scheduledObserver = function() { + run.scheduleOnce('render', this, stateCheckedObserver); + }; + + addObserver(root, path, target, scheduledObserver); + + this.one('willClearRender', function() { + removeObserver(root, path, target, scheduledObserver); + }); + } + + }); + + /* + Describe how the specified actions should behave in the various + states that a view can exist in. Possible states: + + * preRender: when a view is first instantiated, and after its + element was destroyed, it is in the preRender state + * inBuffer: once a view has been rendered, but before it has + been inserted into the DOM, it is in the inBuffer state + * hasElement: the DOM representation of the view is created, + and is ready to be inserted + * inDOM: once a view has been inserted into the DOM it is in + the inDOM state. A view spends the vast majority of its + existence in this state. + * destroyed: once a view has been destroyed (using the destroy + method), it is in this state. No further actions can be invoked + on a destroyed view. + */ + + // in the destroyed state, everything is illegal + + // before rendering has begun, all legal manipulations are noops. + + // inside the buffer, legal manipulations are done on the buffer + + // once the view has been inserted into the DOM, legal manipulations + // are done on the DOM element. + + function notifyMutationListeners() { + run.once(View, 'notifyMutationListeners'); + } + + var DOMManager = { + prepend: function(view, html) { + view.$().prepend(html); + notifyMutationListeners(); + }, + + after: function(view, html) { + view.$().after(html); + notifyMutationListeners(); + }, + + html: function(view, html) { + view.$().html(html); + notifyMutationListeners(); + }, + + replace: function(view) { + var element = get(view, 'element'); + + set(view, 'element', null); + + view._insertElementLater(function() { + jQuery(element).replaceWith(get(view, 'element')); + notifyMutationListeners(); + }); + }, + + remove: function(view) { + view.$().remove(); + notifyMutationListeners(); + }, + + empty: function(view) { + view.$().empty(); + notifyMutationListeners(); + } + }; + + View.reopen({ + domManager: DOMManager + }); + + View.reopenClass({ + + /** + Parse a path and return an object which holds the parsed properties. + + For example a path like "content.isEnabled:enabled:disabled" will return the + following object: + + ```javascript + { + path: "content.isEnabled", + className: "enabled", + falsyClassName: "disabled", + classNames: ":enabled:disabled" + } + ``` + + @method _parsePropertyPath + @static + @private + */ + _parsePropertyPath: function(path) { + var split = path.split(':'), + propertyPath = split[0], + classNames = "", + className, + falsyClassName; + + // check if the property is defined as prop:class or prop:trueClass:falseClass + if (split.length > 1) { + className = split[1]; + if (split.length === 3) { falsyClassName = split[2]; } + + classNames = ':' + className; + if (falsyClassName) { classNames += ":" + falsyClassName; } + } + + return { + path: propertyPath, + classNames: classNames, + className: (className === '') ? undefined : className, + falsyClassName: falsyClassName + }; + }, + + /** + Get the class name for a given value, based on the path, optional + `className` and optional `falsyClassName`. + + - if a `className` or `falsyClassName` has been specified: + - if the value is truthy and `className` has been specified, + `className` is returned + - if the value is falsy and `falsyClassName` has been specified, + `falsyClassName` is returned + - otherwise `null` is returned + - if the value is `true`, the dasherized last part of the supplied path + is returned + - if the value is not `false`, `undefined` or `null`, the `value` + is returned + - if none of the above rules apply, `null` is returned + + @method _classStringForValue + @param path + @param val + @param className + @param falsyClassName + @static + @private + */ + _classStringForValue: function(path, val, className, falsyClassName) { + if(isArray(val)) { + val = get(val, 'length') !== 0; + } + + // When using the colon syntax, evaluate the truthiness or falsiness + // of the value to determine which className to return + if (className || falsyClassName) { + if (className && !!val) { + return className; + + } else if (falsyClassName && !val) { + return falsyClassName; + + } else { + return null; + } + + // If value is a Boolean and true, return the dasherized property + // name. + } else if (val === true) { + // Normalize property path to be suitable for use + // as a class name. For exaple, content.foo.barBaz + // becomes bar-baz. + var parts = path.split('.'); + return dasherize(parts[parts.length-1]); + + // If the value is not false, undefined, or null, return the current + // value of the property. + } else if (val !== false && val != null) { + return val; + + // Nothing to display. Return null so that the old class is removed + // but no new class is added. + } else { + return null; + } + } + }); + + var mutation = EmberObject.extend(Evented).create(); + + View.addMutationListener = function(callback) { + mutation.on('change', callback); + }; + + View.removeMutationListener = function(callback) { + mutation.off('change', callback); + }; + + View.notifyMutationListeners = function() { + mutation.trigger('change'); + }; + + /** + Global views hash + + @property views + @static + @type Hash + */ + View.views = {}; + + // If someone overrides the child views computed property when + // defining their class, we want to be able to process the user's + // supplied childViews and then restore the original computed property + // at view initialization time. This happens in Ember.ContainerView's init + // method. + View.childViewsProperty = childViewsProperty; + + View.applyAttributeBindings = function(elem, name, value) { + var type = typeOf(value); + + // if this changes, also change the logic in ember-handlebars/lib/helpers/binding.js + if (name !== 'value' && (type === 'string' || (type === 'number' && !isNaN(value)))) { + if (value !== elem.attr(name)) { + elem.attr(name, value); + } + } else if (name === 'value' || type === 'boolean') { + if (isNone(value) || value === false) { + // `null`, `undefined` or `false` should remove attribute + elem.removeAttr(name); + // In IE8 `prop` couldn't remove attribute when name is `required`. + if (name === 'required') { + elem.removeProp(name); + } else { + elem.prop(name, ''); + } + } else if (value !== elem.prop(name)) { + // value should always be properties + elem.prop(name, value); + } + } else if (!value) { + elem.removeAttr(name); + } + }; + + __exports__["default"] = View; + }); +define("ember-views/views/view_collection", + ["ember-metal/enumerable_utils","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var forEach = __dependency1__.forEach; + + function ViewCollection(initialViews) { + var views = this.views = initialViews || []; + this.length = views.length; + } + + ViewCollection.prototype = { + length: 0, + + trigger: function(eventName) { + var views = this.views, view; + for (var i = 0, l = views.length; i < l; i++) { + view = views[i]; + if (view.trigger) { view.trigger(eventName); } + } + }, + + triggerRecursively: function(eventName) { + var views = this.views; + for (var i = 0, l = views.length; i < l; i++) { + views[i].triggerRecursively(eventName); + } + }, + + invokeRecursively: function(fn) { + var views = this.views, view; + + for (var i = 0, l = views.length; i < l; i++) { + view = views[i]; + fn(view); + } + }, + + transitionTo: function(state, children) { + var views = this.views; + for (var i = 0, l = views.length; i < l; i++) { + views[i]._transitionTo(state, children); + } + }, + + push: function() { + this.length += arguments.length; + var views = this.views; + return views.push.apply(views, arguments); + }, + + objectAt: function(idx) { + return this.views[idx]; + }, + + forEach: function(callback) { + var views = this.views; + return forEach(views, callback); + }, + + clear: function() { + this.length = 0; + this.views.length = 0; + } + }; + + __exports__["default"] = ViewCollection; + }); +define("ember", + ["ember-metal","ember-runtime","ember-handlebars","ember-views","ember-routing","ember-routing-handlebars","ember-application","ember-extension-support"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__) { + "use strict"; + // require the main entry points for each of these packages + // this is so that the global exports occur properly + + // do this to ensure that Ember.Test is defined properly on the global + // if it is present. + if (Ember.__loader.registry['ember-testing']) { + requireModule('ember-testing'); + } + + /** + Ember + + @module ember + */ + + function throwWithMessage(msg) { + return function() { + throw new Ember.Error(msg); + }; + } + + function generateRemovedClass(className) { + var msg = " has been moved into a plugin: https://github.com/emberjs/ember-states"; + + return { + extend: throwWithMessage(className + msg), + create: throwWithMessage(className + msg) + }; + } + + Ember.StateManager = generateRemovedClass("Ember.StateManager"); + + /** + This was exported to ember-states plugin for v 1.0.0 release. See: https://github.com/emberjs/ember-states + + @class StateManager + @namespace Ember + */ + + Ember.State = generateRemovedClass("Ember.State"); + + /** + This was exported to ember-states plugin for v 1.0.0 release. See: https://github.com/emberjs/ember-states + + @class State + @namespace Ember + */ + }); +define("metamorph", + [], + function() { + "use strict"; + // ========================================================================== + // Project: metamorph + // Copyright: ©2014 Tilde, Inc. All rights reserved. + // ========================================================================== + + var K = function() {}, + guid = 0, + disableRange = (function(){ + if ('undefined' !== typeof MetamorphENV) { + return MetamorphENV.DISABLE_RANGE_API; + } else if ('undefined' !== ENV) { + return ENV.DISABLE_RANGE_API; + } else { + return false; + } + })(), + + // Feature-detect the W3C range API, the extended check is for IE9 which only partially supports ranges + supportsRange = (!disableRange) && typeof document !== 'undefined' && ('createRange' in document) && (typeof Range !== 'undefined') && Range.prototype.createContextualFragment, + + // Internet Explorer prior to 9 does not allow setting innerHTML if the first element + // is a "zero-scope" element. This problem can be worked around by making + // the first node an invisible text node. We, like Modernizr, use ­ + needsShy = typeof document !== 'undefined' && (function() { + var testEl = document.createElement('div'); + testEl.innerHTML = "
    "; + testEl.firstChild.innerHTML = ""; + return testEl.firstChild.innerHTML === ''; + })(), + + + // IE 8 (and likely earlier) likes to move whitespace preceeding + // a script tag to appear after it. This means that we can + // accidentally remove whitespace when updating a morph. + movesWhitespace = document && (function() { + var testEl = document.createElement('div'); + testEl.innerHTML = "Test: Value"; + return testEl.childNodes[0].nodeValue === 'Test:' && + testEl.childNodes[2].nodeValue === ' Value'; + })(); + + // Constructor that supports either Metamorph('foo') or new + // Metamorph('foo'); + // + // Takes a string of HTML as the argument. + + var Metamorph = function(html) { + var self; + + if (this instanceof Metamorph) { + self = this; + } else { + self = new K(); + } + + self.innerHTML = html; + var myGuid = 'metamorph-'+(guid++); + self.start = myGuid + '-start'; + self.end = myGuid + '-end'; + + return self; + }; + + K.prototype = Metamorph.prototype; + + var rangeFor, htmlFunc, removeFunc, outerHTMLFunc, appendToFunc, afterFunc, prependFunc, startTagFunc, endTagFunc; + + outerHTMLFunc = function() { + return this.startTag() + this.innerHTML + this.endTag(); + }; + + startTagFunc = function() { + /* + * We replace chevron by its hex code in order to prevent escaping problems. + * Check this thread for more explaination: + * http://stackoverflow.com/questions/8231048/why-use-x3c-instead-of-when-generating-html-from-javascript + */ + return "hi"; + * div.firstChild.firstChild.tagName //=> "" + * + * If our script markers are inside such a node, we need to find that + * node and use *it* as the marker. + */ + var realNode = function(start) { + while (start.parentNode.tagName === "") { + start = start.parentNode; + } + + return start; + }; + + /* + * When automatically adding a tbody, Internet Explorer inserts the + * tbody immediately before the first . Other browsers create it + * before the first node, no matter what. + * + * This means the the following code: + * + * div = document.createElement("div"); + * div.innerHTML = "
    hi
    + * + * Generates the following DOM in IE: + * + * + div + * + table + * - script id='first' + * + tbody + * + tr + * + td + * - "hi" + * - script id='last' + * + * Which means that the two script tags, even though they were + * inserted at the same point in the hierarchy in the original + * HTML, now have different parents. + * + * This code reparents the first script tag by making it the tbody's + * first child. + * + */ + var fixParentage = function(start, end) { + if (start.parentNode !== end.parentNode) { + end.parentNode.insertBefore(start, end.parentNode.firstChild); + } + }; + + htmlFunc = function(html, outerToo) { + // get the real starting node. see realNode for details. + var start = realNode(document.getElementById(this.start)); + var end = document.getElementById(this.end); + var parentNode = end.parentNode; + var node, nextSibling, last; + + // make sure that the start and end nodes share the same + // parent. If not, fix it. + fixParentage(start, end); + + // remove all of the nodes after the starting placeholder and + // before the ending placeholder. + node = start.nextSibling; + while (node) { + nextSibling = node.nextSibling; + last = node === end; + + // if this is the last node, and we want to remove it as well, + // set the `end` node to the next sibling. This is because + // for the rest of the function, we insert the new nodes + // before the end (note that insertBefore(node, null) is + // the same as appendChild(node)). + // + // if we do not want to remove it, just break. + if (last) { + if (outerToo) { end = node.nextSibling; } else { break; } + } + + node.parentNode.removeChild(node); + + // if this is the last node and we didn't break before + // (because we wanted to remove the outer nodes), break + // now. + if (last) { break; } + + node = nextSibling; + } + + // get the first node for the HTML string, even in cases like + // tables and lists where a simple innerHTML on a div would + // swallow some of the content. + node = firstNodeFor(start.parentNode, html); + + if (outerToo) { + start.parentNode.removeChild(start); + } + + // copy the nodes for the HTML between the starting and ending + // placeholder. + while (node) { + nextSibling = node.nextSibling; + parentNode.insertBefore(node, end); + node = nextSibling; + } + }; + + // remove the nodes in the DOM representing this metamorph. + // + // this includes the starting and ending placeholders. + removeFunc = function() { + var start = realNode(document.getElementById(this.start)); + var end = document.getElementById(this.end); + + this.html(''); + start.parentNode.removeChild(start); + end.parentNode.removeChild(end); + }; + + appendToFunc = function(parentNode) { + var node = firstNodeFor(parentNode, this.outerHTML()); + var nextSibling; + + while (node) { + nextSibling = node.nextSibling; + parentNode.appendChild(node); + node = nextSibling; + } + }; + + afterFunc = function(html) { + // get the real starting node. see realNode for details. + var end = document.getElementById(this.end); + var insertBefore = end.nextSibling; + var parentNode = end.parentNode; + var nextSibling; + var node; + + // get the first node for the HTML string, even in cases like + // tables and lists where a simple innerHTML on a div would + // swallow some of the content. + node = firstNodeFor(parentNode, html); + + // copy the nodes for the HTML between the starting and ending + // placeholder. + while (node) { + nextSibling = node.nextSibling; + parentNode.insertBefore(node, insertBefore); + node = nextSibling; + } + }; + + prependFunc = function(html) { + var start = document.getElementById(this.start); + var parentNode = start.parentNode; + var nextSibling; + var node; + + node = firstNodeFor(parentNode, html); + var insertBefore = start.nextSibling; + + while (node) { + nextSibling = node.nextSibling; + parentNode.insertBefore(node, insertBefore); + node = nextSibling; + } + }; + } + + Metamorph.prototype.html = function(html) { + this.checkRemoved(); + if (html === undefined) { return this.innerHTML; } + + htmlFunc.call(this, html); + + this.innerHTML = html; + }; + + Metamorph.prototype.replaceWith = function(html) { + this.checkRemoved(); + htmlFunc.call(this, html, true); + }; + + Metamorph.prototype.remove = removeFunc; + Metamorph.prototype.outerHTML = outerHTMLFunc; + Metamorph.prototype.appendTo = appendToFunc; + Metamorph.prototype.after = afterFunc; + Metamorph.prototype.prepend = prependFunc; + Metamorph.prototype.startTag = startTagFunc; + Metamorph.prototype.endTag = endTagFunc; + + Metamorph.prototype.isRemoved = function() { + var before = document.getElementById(this.start); + var after = document.getElementById(this.end); + + return !before || !after; + }; + + Metamorph.prototype.checkRemoved = function() { + if (this.isRemoved()) { + throw new Error("Cannot perform operations on a Metamorph that is not in the DOM."); + } + }; + + return Metamorph; + }); + +define("route-recognizer", + ["route-recognizer/dsl","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var map = __dependency1__["default"]; + + var specials = [ + '/', '.', '*', '+', '?', '|', + '(', ')', '[', ']', '{', '}', '\\' + ]; + + var escapeRegex = new RegExp('(\\' + specials.join('|\\') + ')', 'g'); + + function isArray(test) { + return Object.prototype.toString.call(test) === "[object Array]"; + } + + // A Segment represents a segment in the original route description. + // Each Segment type provides an `eachChar` and `regex` method. + // + // The `eachChar` method invokes the callback with one or more character + // specifications. A character specification consumes one or more input + // characters. + // + // The `regex` method returns a regex fragment for the segment. If the + // segment is a dynamic of star segment, the regex fragment also includes + // a capture. + // + // A character specification contains: + // + // * `validChars`: a String with a list of all valid characters, or + // * `invalidChars`: a String with a list of all invalid characters + // * `repeat`: true if the character specification can repeat + + function StaticSegment(string) { this.string = string; } + StaticSegment.prototype = { + eachChar: function(callback) { + var string = this.string, ch; + + for (var i=0, l=string.length; i " + n.nextStates.map(function(s) { return s.debug() }).join(" or ") + " )"; + }).join(", ") + } + END IF **/ + + // This is a somewhat naive strategy, but should work in a lot of cases + // A better strategy would properly resolve /posts/:id/new and /posts/edit/:id. + // + // This strategy generally prefers more static and less dynamic matching. + // Specifically, it + // + // * prefers fewer stars to more, then + // * prefers using stars for less of the match to more, then + // * prefers fewer dynamic segments to more, then + // * prefers more static segments to more + function sortSolutions(states) { + return states.sort(function(a, b) { + if (a.types.stars !== b.types.stars) { return a.types.stars - b.types.stars; } + + if (a.types.stars) { + if (a.types.statics !== b.types.statics) { return b.types.statics - a.types.statics; } + if (a.types.dynamics !== b.types.dynamics) { return b.types.dynamics - a.types.dynamics; } + } + + if (a.types.dynamics !== b.types.dynamics) { return a.types.dynamics - b.types.dynamics; } + if (a.types.statics !== b.types.statics) { return b.types.statics - a.types.statics; } + + return 0; + }); + } + + function recognizeChar(states, ch) { + var nextStates = []; + + for (var i=0, l=states.length; i 2 && key.slice(keyLength -2) === '[]') { + isArray = true; + key = key.slice(0, keyLength - 2); + if(!queryParams[key]) { + queryParams[key] = []; + } + } + value = pair[1] ? decodeURIComponent(pair[1]) : ''; + } + if (isArray) { + queryParams[key].push(value); + } else { + queryParams[key] = value; + } + } + return queryParams; + }, + + recognize: function(path) { + var states = [ this.rootState ], + pathLen, i, l, queryStart, queryParams = {}, + isSlashDropped = false; + + queryStart = path.indexOf('?'); + if (queryStart !== -1) { + var queryString = path.substr(queryStart + 1, path.length); + path = path.substr(0, queryStart); + queryParams = this.parseQueryString(queryString); + } + + path = decodeURI(path); + + // DEBUG GROUP path + + if (path.charAt(0) !== "/") { path = "/" + path; } + + pathLen = path.length; + if (pathLen > 1 && path.charAt(pathLen - 1) === "/") { + path = path.substr(0, pathLen - 1); + isSlashDropped = true; + } + + for (i=0, l=path.length; i= 0 && proceed; --i) { + var route = routes[i]; + recognizer.add(routes, { as: route.handler }); + proceed = route.path === '/' || route.path === '' || route.handler.slice(-6) === '.index'; + } + }); + }, + + hasRoute: function(route) { + return this.recognizer.hasRoute(route); + }, + + queryParamsTransition: function(changelist, wasTransitioning, oldState, newState) { + var router = this; + + fireQueryParamDidChange(this, newState, changelist); + + if (!wasTransitioning && this.activeTransition) { + // One of the handlers in queryParamsDidChange + // caused a transition. Just return that transition. + return this.activeTransition; + } else { + // Running queryParamsDidChange didn't change anything. + // Just update query params and be on our way. + + // We have to return a noop transition that will + // perform a URL update at the end. This gives + // the user the ability to set the url update + // method (default is replaceState). + var newTransition = new Transition(this); + newTransition.queryParamsOnly = true; + + oldState.queryParams = finalizeQueryParamChange(this, newState.handlerInfos, newState.queryParams, newTransition); + + newTransition.promise = newTransition.promise.then(function(result) { + updateURL(newTransition, oldState, true); + if (router.didTransition) { + router.didTransition(router.currentHandlerInfos); + } + return result; + }, null, promiseLabel("Transition complete")); + return newTransition; + } + }, + + // NOTE: this doesn't really belong here, but here + // it shall remain until our ES6 transpiler can + // handle cyclical deps. + transitionByIntent: function(intent, isIntermediate) { + + var wasTransitioning = !!this.activeTransition; + var oldState = wasTransitioning ? this.activeTransition.state : this.state; + var newTransition; + var router = this; + + try { + var newState = intent.applyToState(oldState, this.recognizer, this.getHandler, isIntermediate); + var queryParamChangelist = getChangelist(oldState.queryParams, newState.queryParams); + + if (handlerInfosEqual(newState.handlerInfos, oldState.handlerInfos)) { + + // This is a no-op transition. See if query params changed. + if (queryParamChangelist) { + newTransition = this.queryParamsTransition(queryParamChangelist, wasTransitioning, oldState, newState); + if (newTransition) { + return newTransition; + } + } + + // No-op. No need to create a new transition. + return new Transition(this); + } + + if (isIntermediate) { + setupContexts(this, newState); + return; + } + + // Create a new transition to the destination route. + newTransition = new Transition(this, intent, newState); + + // Abort and usurp any previously active transition. + if (this.activeTransition) { + this.activeTransition.abort(); + } + this.activeTransition = newTransition; + + // Transition promises by default resolve with resolved state. + // For our purposes, swap out the promise to resolve + // after the transition has been finalized. + newTransition.promise = newTransition.promise.then(function(result) { + return finalizeTransition(newTransition, result.state); + }, null, promiseLabel("Settle transition promise when transition is finalized")); + + if (!wasTransitioning) { + notifyExistingHandlers(this, newState, newTransition); + } + + fireQueryParamDidChange(this, newState, queryParamChangelist); + + return newTransition; + } catch(e) { + return new Transition(this, intent, null, e); + } + }, + + /** + Clears the current and target route handlers and triggers exit + on each of them starting at the leaf and traversing up through + its ancestors. + */ + reset: function() { + if (this.state) { + forEach(this.state.handlerInfos.slice().reverse(), function(handlerInfo) { + var handler = handlerInfo.handler; + callHook(handler, 'exit'); + }); + } + + this.state = new TransitionState(); + this.currentHandlerInfos = null; + }, + + activeTransition: null, + + /** + var handler = handlerInfo.handler; + The entry point for handling a change to the URL (usually + via the back and forward button). + + Returns an Array of handlers and the parameters associated + with those parameters. + + @param {String} url a URL to process + + @return {Array} an Array of `[handler, parameter]` tuples + */ + handleURL: function(url) { + // Perform a URL-based transition, but don't change + // the URL afterward, since it already happened. + var args = slice.call(arguments); + if (url.charAt(0) !== '/') { args[0] = '/' + url; } + + return doTransition(this, args).method(null); + }, + + /** + Hook point for updating the URL. + + @param {String} url a URL to update to + */ + updateURL: function() { + throw new Error("updateURL is not implemented"); + }, + + /** + Hook point for replacing the current URL, i.e. with replaceState + + By default this behaves the same as `updateURL` + + @param {String} url a URL to update to + */ + replaceURL: function(url) { + this.updateURL(url); + }, + + /** + Transition into the specified named route. + + If necessary, trigger the exit callback on any handlers + that are no longer represented by the target route. + + @param {String} name the name of the route + */ + transitionTo: function(name) { + return doTransition(this, arguments); + }, + + intermediateTransitionTo: function(name) { + return doTransition(this, arguments, true); + }, + + refresh: function(pivotHandler) { + var state = this.activeTransition ? this.activeTransition.state : this.state; + var handlerInfos = state.handlerInfos; + var params = {}; + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var handlerInfo = handlerInfos[i]; + params[handlerInfo.name] = handlerInfo.params || {}; + } + + log(this, "Starting a refresh transition"); + var intent = new NamedTransitionIntent({ + name: handlerInfos[handlerInfos.length - 1].name, + pivotHandler: pivotHandler || handlerInfos[0].handler, + contexts: [], // TODO collect contexts...? + queryParams: this._changedQueryParams || state.queryParams || {} + }); + + return this.transitionByIntent(intent, false); + }, + + /** + Identical to `transitionTo` except that the current URL will be replaced + if possible. + + This method is intended primarily for use with `replaceState`. + + @param {String} name the name of the route + */ + replaceWith: function(name) { + return doTransition(this, arguments).method('replace'); + }, + + /** + Take a named route and context objects and generate a + URL. + + @param {String} name the name of the route to generate + a URL for + @param {...Object} objects a list of objects to serialize + + @return {String} a URL + */ + generate: function(handlerName) { + + var partitionedArgs = extractQueryParams(slice.call(arguments, 1)), + suppliedParams = partitionedArgs[0], + queryParams = partitionedArgs[1]; + + // Construct a TransitionIntent with the provided params + // and apply it to the present state of the router. + var intent = new NamedTransitionIntent({ name: handlerName, contexts: suppliedParams }); + var state = intent.applyToState(this.state, this.recognizer, this.getHandler); + var params = {}; + + for (var i = 0, len = state.handlerInfos.length; i < len; ++i) { + var handlerInfo = state.handlerInfos[i]; + var handlerParams = handlerInfo.serialize(); + merge(params, handlerParams); + } + params.queryParams = queryParams; + + return this.recognizer.generate(handlerName, params); + }, + + applyIntent: function(handlerName, contexts) { + var intent = new NamedTransitionIntent({ + name: handlerName, + contexts: contexts + }); + + var state = this.activeTransition && this.activeTransition.state || this.state; + return intent.applyToState(state, this.recognizer, this.getHandler); + }, + + isActiveIntent: function(handlerName, contexts, queryParams) { + var targetHandlerInfos = this.state.handlerInfos, + found = false, names, object, handlerInfo, handlerObj, i, len; + + if (!targetHandlerInfos.length) { return false; } + + var targetHandler = targetHandlerInfos[targetHandlerInfos.length - 1].name; + var recogHandlers = this.recognizer.handlersFor(targetHandler); + + var index = 0; + for (len = recogHandlers.length; index < len; ++index) { + handlerInfo = targetHandlerInfos[index]; + if (handlerInfo.name === handlerName) { break; } + } + + if (index === recogHandlers.length) { + // The provided route name isn't even in the route hierarchy. + return false; + } + + var state = new TransitionState(); + state.handlerInfos = targetHandlerInfos.slice(0, index + 1); + recogHandlers = recogHandlers.slice(0, index + 1); + + var intent = new NamedTransitionIntent({ + name: targetHandler, + contexts: contexts + }); + + var newState = intent.applyToHandlers(state, recogHandlers, this.getHandler, targetHandler, true, true); + + var handlersEqual = handlerInfosEqual(newState.handlerInfos, state.handlerInfos); + if (!queryParams || !handlersEqual) { + return handlersEqual; + } + + // Get a hash of QPs that will still be active on new route + var activeQPsOnNewHandler = {}; + merge(activeQPsOnNewHandler, queryParams); + + var activeQueryParams = this.state.queryParams; + for (var key in activeQueryParams) { + if (activeQueryParams.hasOwnProperty(key) && + activeQPsOnNewHandler.hasOwnProperty(key)) { + activeQPsOnNewHandler[key] = activeQueryParams[key]; + } + } + + return handlersEqual && !getChangelist(activeQPsOnNewHandler, queryParams); + }, + + isActive: function(handlerName) { + var partitionedArgs = extractQueryParams(slice.call(arguments, 1)); + return this.isActiveIntent(handlerName, partitionedArgs[0], partitionedArgs[1]); + }, + + trigger: function(name) { + var args = slice.call(arguments); + trigger(this, this.currentHandlerInfos, false, args); + }, + + /** + Hook point for logging transition status updates. + + @param {String} message The message to log. + */ + log: null, + + _willChangeContextEvent: 'willChangeContext', + _triggerWillChangeContext: function(handlerInfos, newTransition) { + trigger(this, handlerInfos, true, [this._willChangeContextEvent, newTransition]); + }, + + _triggerWillLeave: function(handlerInfos, newTransition, leavingChecker) { + trigger(this, handlerInfos, true, ['willLeave', newTransition, leavingChecker]); + } + }; + + /** + @private + + Fires queryParamsDidChange event + */ + function fireQueryParamDidChange(router, newState, queryParamChangelist) { + // If queryParams changed trigger event + if (queryParamChangelist) { + + // This is a little hacky but we need some way of storing + // changed query params given that no activeTransition + // is guaranteed to have occurred. + router._changedQueryParams = queryParamChangelist.all; + trigger(router, newState.handlerInfos, true, ['queryParamsDidChange', queryParamChangelist.changed, queryParamChangelist.all, queryParamChangelist.removed]); + router._changedQueryParams = null; + } + } + + /** + @private + + Takes an Array of `HandlerInfo`s, figures out which ones are + exiting, entering, or changing contexts, and calls the + proper handler hooks. + + For example, consider the following tree of handlers. Each handler is + followed by the URL segment it handles. + + ``` + |~index ("/") + | |~posts ("/posts") + | | |-showPost ("/:id") + | | |-newPost ("/new") + | | |-editPost ("/edit") + | |~about ("/about/:id") + ``` + + Consider the following transitions: + + 1. A URL transition to `/posts/1`. + 1. Triggers the `*model` callbacks on the + `index`, `posts`, and `showPost` handlers + 2. Triggers the `enter` callback on the same + 3. Triggers the `setup` callback on the same + 2. A direct transition to `newPost` + 1. Triggers the `exit` callback on `showPost` + 2. Triggers the `enter` callback on `newPost` + 3. Triggers the `setup` callback on `newPost` + 3. A direct transition to `about` with a specified + context object + 1. Triggers the `exit` callback on `newPost` + and `posts` + 2. Triggers the `serialize` callback on `about` + 3. Triggers the `enter` callback on `about` + 4. Triggers the `setup` callback on `about` + + @param {Router} transition + @param {TransitionState} newState + */ + function setupContexts(router, newState, transition) { + var partition = partitionHandlers(router.state, newState); + + forEach(partition.exited, function(handlerInfo) { + var handler = handlerInfo.handler; + delete handler.context; + + callHook(handler, 'reset', true, transition); + callHook(handler, 'exit', transition); + }); + + var oldState = router.oldState = router.state; + router.state = newState; + var currentHandlerInfos = router.currentHandlerInfos = partition.unchanged.slice(); + + try { + forEach(partition.reset, function(handlerInfo) { + var handler = handlerInfo.handler; + callHook(handler, 'reset', false, transition); + }); + + forEach(partition.updatedContext, function(handlerInfo) { + return handlerEnteredOrUpdated(currentHandlerInfos, handlerInfo, false, transition); + }); + + forEach(partition.entered, function(handlerInfo) { + return handlerEnteredOrUpdated(currentHandlerInfos, handlerInfo, true, transition); + }); + } catch(e) { + router.state = oldState; + router.currentHandlerInfos = oldState.handlerInfos; + throw e; + } + + router.state.queryParams = finalizeQueryParamChange(router, currentHandlerInfos, newState.queryParams, transition); + } + + + /** + @private + + Helper method used by setupContexts. Handles errors or redirects + that may happen in enter/setup. + */ + function handlerEnteredOrUpdated(currentHandlerInfos, handlerInfo, enter, transition) { + + var handler = handlerInfo.handler, + context = handlerInfo.context; + + callHook(handler, 'enter', transition); + if (transition && transition.isAborted) { + throw new TransitionAborted(); + } + + handler.context = context; + callHook(handler, 'contextDidChange'); + + callHook(handler, 'setup', context, transition); + if (transition && transition.isAborted) { + throw new TransitionAborted(); + } + + currentHandlerInfos.push(handlerInfo); + + return true; + } + + + /** + @private + + This function is called when transitioning from one URL to + another to determine which handlers are no longer active, + which handlers are newly active, and which handlers remain + active but have their context changed. + + Take a list of old handlers and new handlers and partition + them into four buckets: + + * unchanged: the handler was active in both the old and + new URL, and its context remains the same + * updated context: the handler was active in both the + old and new URL, but its context changed. The handler's + `setup` method, if any, will be called with the new + context. + * exited: the handler was active in the old URL, but is + no longer active. + * entered: the handler was not active in the old URL, but + is now active. + + The PartitionedHandlers structure has four fields: + + * `updatedContext`: a list of `HandlerInfo` objects that + represent handlers that remain active but have a changed + context + * `entered`: a list of `HandlerInfo` objects that represent + handlers that are newly active + * `exited`: a list of `HandlerInfo` objects that are no + longer active. + * `unchanged`: a list of `HanderInfo` objects that remain active. + + @param {Array[HandlerInfo]} oldHandlers a list of the handler + information for the previous URL (or `[]` if this is the + first handled transition) + @param {Array[HandlerInfo]} newHandlers a list of the handler + information for the new URL + + @return {Partition} + */ + function partitionHandlers(oldState, newState) { + var oldHandlers = oldState.handlerInfos; + var newHandlers = newState.handlerInfos; + + var handlers = { + updatedContext: [], + exited: [], + entered: [], + unchanged: [] + }; + + var handlerChanged, contextChanged = false, i, l; + + for (i=0, l=newHandlers.length; i= 0; --i) { + var handlerInfo = handlerInfos[i]; + merge(params, handlerInfo.params); + if (handlerInfo.handler.inaccessibleByURL) { + urlMethod = null; + } + } + + if (urlMethod) { + params.queryParams = transition._visibleQueryParams || state.queryParams; + var url = router.recognizer.generate(handlerName, params); + + if (urlMethod === 'replace') { + router.replaceURL(url); + } else { + router.updateURL(url); + } + } + } + + /** + @private + + Updates the URL (if necessary) and calls `setupContexts` + to update the router's array of `currentHandlerInfos`. + */ + function finalizeTransition(transition, newState) { + + try { + log(transition.router, transition.sequence, "Resolved all models on destination route; finalizing transition."); + + var router = transition.router, + handlerInfos = newState.handlerInfos, + seq = transition.sequence; + + // Run all the necessary enter/setup/exit hooks + setupContexts(router, newState, transition); + + // Check if a redirect occurred in enter/setup + if (transition.isAborted) { + // TODO: cleaner way? distinguish b/w targetHandlerInfos? + router.state.handlerInfos = router.currentHandlerInfos; + return Promise.reject(logAbort(transition)); + } + + updateURL(transition, newState, transition.intent.url); + + transition.isActive = false; + router.activeTransition = null; + + trigger(router, router.currentHandlerInfos, true, ['didTransition']); + + if (router.didTransition) { + router.didTransition(router.currentHandlerInfos); + } + + log(router, transition.sequence, "TRANSITION COMPLETE."); + + // Resolve with the final handler. + return handlerInfos[handlerInfos.length - 1].handler; + } catch(e) { + if (!((e instanceof TransitionAborted))) { + //var erroneousHandler = handlerInfos.pop(); + var infos = transition.state.handlerInfos; + transition.trigger(true, 'error', e, transition, infos[infos.length-1].handler); + transition.abort(); + } + + throw e; + } + } + + /** + @private + + Begins and returns a Transition based on the provided + arguments. Accepts arguments in the form of both URL + transitions and named transitions. + + @param {Router} router + @param {Array[Object]} args arguments passed to transitionTo, + replaceWith, or handleURL + */ + function doTransition(router, args, isIntermediate) { + // Normalize blank transitions to root URL transitions. + var name = args[0] || '/'; + + var lastArg = args[args.length-1]; + var queryParams = {}; + if (lastArg && lastArg.hasOwnProperty('queryParams')) { + queryParams = pop.call(args).queryParams; + } + + var intent; + if (args.length === 0) { + + log(router, "Updating query params"); + + // A query param update is really just a transition + // into the route you're already on. + var handlerInfos = router.state.handlerInfos; + intent = new NamedTransitionIntent({ + name: handlerInfos[handlerInfos.length - 1].name, + contexts: [], + queryParams: queryParams + }); + + } else if (name.charAt(0) === '/') { + + log(router, "Attempting URL transition to " + name); + intent = new URLTransitionIntent({ url: name }); + + } else { + + log(router, "Attempting transition to " + name); + intent = new NamedTransitionIntent({ + name: args[0], + contexts: slice.call(args, 1), + queryParams: queryParams + }); + } + + return router.transitionByIntent(intent, isIntermediate); + } + + function handlerInfosEqual(handlerInfos, otherHandlerInfos) { + if (handlerInfos.length !== otherHandlerInfos.length) { + return false; + } + + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + if (handlerInfos[i] !== otherHandlerInfos[i]) { + return false; + } + } + return true; + } + + function finalizeQueryParamChange(router, resolvedHandlers, newQueryParams, transition) { + // We fire a finalizeQueryParamChange event which + // gives the new route hierarchy a chance to tell + // us which query params it's consuming and what + // their final values are. If a query param is + // no longer consumed in the final route hierarchy, + // its serialized segment will be removed + // from the URL. + + for (var k in newQueryParams) { + if (newQueryParams.hasOwnProperty(k) && + newQueryParams[k] === null) { + delete newQueryParams[k]; + } + } + + var finalQueryParamsArray = []; + trigger(router, resolvedHandlers, true, ['finalizeQueryParamChange', newQueryParams, finalQueryParamsArray, transition]); + + if (transition) { + transition._visibleQueryParams = {}; + } + + var finalQueryParams = {}; + for (var i = 0, len = finalQueryParamsArray.length; i < len; ++i) { + var qp = finalQueryParamsArray[i]; + finalQueryParams[qp.key] = qp.value; + if (transition && qp.visible !== false) { + transition._visibleQueryParams[qp.key] = qp.value; + } + } + return finalQueryParams; + } + + function notifyExistingHandlers(router, newState, newTransition) { + var oldHandlers = router.state.handlerInfos, + changing = [], + leavingIndex = null, + leaving, leavingChecker, i, oldHandlerLen, oldHandler, newHandler; + + oldHandlerLen = oldHandlers.length; + for (i = 0; i < oldHandlerLen; i++) { + oldHandler = oldHandlers[i]; + newHandler = newState.handlerInfos[i]; + + if (!newHandler || oldHandler.name !== newHandler.name) { + leavingIndex = i; + break; + } + + if (!newHandler.isResolved) { + changing.push(oldHandler); + } + } + + if (leavingIndex !== null) { + leaving = oldHandlers.slice(leavingIndex, oldHandlerLen); + leavingChecker = function(name) { + for (var h = 0, len = leaving.length; h < len; h++) { + if (leaving[h].name === name) { + return true; + } + } + return false; + }; + + router._triggerWillLeave(leaving, newTransition, leavingChecker); + } + + if (changing.length > 0) { + router._triggerWillChangeContext(changing, newTransition); + } + + trigger(router, oldHandlers, true, ['willTransition', newTransition]); + } + + __exports__["default"] = Router; + }); +define("router/transition-intent", + ["./utils","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var merge = __dependency1__.merge; + + function TransitionIntent(props) { + this.initialize(props); + + // TODO: wat + this.data = this.data || {}; + } + + TransitionIntent.prototype = { + initialize: null, + applyToState: null + }; + + __exports__["default"] = TransitionIntent; + }); +define("router/transition-intent/named-transition-intent", + ["../transition-intent","../transition-state","../handler-info/factory","../utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var TransitionIntent = __dependency1__["default"]; + var TransitionState = __dependency2__["default"]; + var handlerInfoFactory = __dependency3__["default"]; + var isParam = __dependency4__.isParam; + var extractQueryParams = __dependency4__.extractQueryParams; + var merge = __dependency4__.merge; + var subclass = __dependency4__.subclass; + + __exports__["default"] = subclass(TransitionIntent, { + name: null, + pivotHandler: null, + contexts: null, + queryParams: null, + + initialize: function(props) { + this.name = props.name; + this.pivotHandler = props.pivotHandler; + this.contexts = props.contexts || []; + this.queryParams = props.queryParams; + }, + + applyToState: function(oldState, recognizer, getHandler, isIntermediate) { + + var partitionedArgs = extractQueryParams([this.name].concat(this.contexts)), + pureArgs = partitionedArgs[0], + queryParams = partitionedArgs[1], + handlers = recognizer.handlersFor(pureArgs[0]); + + var targetRouteName = handlers[handlers.length-1].handler; + + return this.applyToHandlers(oldState, handlers, getHandler, targetRouteName, isIntermediate); + }, + + applyToHandlers: function(oldState, handlers, getHandler, targetRouteName, isIntermediate, checkingIfActive) { + + var i, len; + var newState = new TransitionState(); + var objects = this.contexts.slice(0); + + var invalidateIndex = handlers.length; + + // Pivot handlers are provided for refresh transitions + if (this.pivotHandler) { + for (i = 0, len = handlers.length; i < len; ++i) { + if (getHandler(handlers[i].handler) === this.pivotHandler) { + invalidateIndex = i; + break; + } + } + } + + var pivotHandlerFound = !this.pivotHandler; + + for (i = handlers.length - 1; i >= 0; --i) { + var result = handlers[i]; + var name = result.handler; + var handler = getHandler(name); + + var oldHandlerInfo = oldState.handlerInfos[i]; + var newHandlerInfo = null; + + if (result.names.length > 0) { + if (i >= invalidateIndex) { + newHandlerInfo = this.createParamHandlerInfo(name, handler, result.names, objects, oldHandlerInfo); + } else { + newHandlerInfo = this.getHandlerInfoForDynamicSegment(name, handler, result.names, objects, oldHandlerInfo, targetRouteName, i); + } + } else { + // This route has no dynamic segment. + // Therefore treat as a param-based handlerInfo + // with empty params. This will cause the `model` + // hook to be called with empty params, which is desirable. + newHandlerInfo = this.createParamHandlerInfo(name, handler, result.names, objects, oldHandlerInfo); + } + + if (checkingIfActive) { + // If we're performing an isActive check, we want to + // serialize URL params with the provided context, but + // ignore mismatches between old and new context. + newHandlerInfo = newHandlerInfo.becomeResolved(null, newHandlerInfo.context); + var oldContext = oldHandlerInfo && oldHandlerInfo.context; + if (result.names.length > 0 && newHandlerInfo.context === oldContext) { + // If contexts match in isActive test, assume params also match. + // This allows for flexibility in not requiring that every last + // handler provide a `serialize` method + newHandlerInfo.params = oldHandlerInfo && oldHandlerInfo.params; + } + newHandlerInfo.context = oldContext; + } + + var handlerToUse = oldHandlerInfo; + if (i >= invalidateIndex || newHandlerInfo.shouldSupercede(oldHandlerInfo)) { + invalidateIndex = Math.min(i, invalidateIndex); + handlerToUse = newHandlerInfo; + } + + if (isIntermediate && !checkingIfActive) { + handlerToUse = handlerToUse.becomeResolved(null, handlerToUse.context); + } + + newState.handlerInfos.unshift(handlerToUse); + } + + if (objects.length > 0) { + throw new Error("More context objects were passed than there are dynamic segments for the route: " + targetRouteName); + } + + if (!isIntermediate) { + this.invalidateChildren(newState.handlerInfos, invalidateIndex); + } + + merge(newState.queryParams, this.queryParams || {}); + + return newState; + }, + + invalidateChildren: function(handlerInfos, invalidateIndex) { + for (var i = invalidateIndex, l = handlerInfos.length; i < l; ++i) { + var handlerInfo = handlerInfos[i]; + handlerInfos[i] = handlerInfos[i].getUnresolved(); + } + }, + + getHandlerInfoForDynamicSegment: function(name, handler, names, objects, oldHandlerInfo, targetRouteName, i) { + + var numNames = names.length; + var objectToUse; + if (objects.length > 0) { + + // Use the objects provided for this transition. + objectToUse = objects[objects.length - 1]; + if (isParam(objectToUse)) { + return this.createParamHandlerInfo(name, handler, names, objects, oldHandlerInfo); + } else { + objects.pop(); + } + } else if (oldHandlerInfo && oldHandlerInfo.name === name) { + // Reuse the matching oldHandlerInfo + return oldHandlerInfo; + } else { + if (this.preTransitionState) { + var preTransitionHandlerInfo = this.preTransitionState.handlerInfos[i]; + objectToUse = preTransitionHandlerInfo && preTransitionHandlerInfo.context; + } else { + // Ideally we should throw this error to provide maximal + // information to the user that not enough context objects + // were provided, but this proves too cumbersome in Ember + // in cases where inner template helpers are evaluated + // before parent helpers un-render, in which cases this + // error somewhat prematurely fires. + //throw new Error("Not enough context objects were provided to complete a transition to " + targetRouteName + ". Specifically, the " + name + " route needs an object that can be serialized into its dynamic URL segments [" + names.join(', ') + "]"); + return oldHandlerInfo; + } + } + + return handlerInfoFactory('object', { + name: name, + handler: handler, + context: objectToUse, + names: names + }); + }, + + createParamHandlerInfo: function(name, handler, names, objects, oldHandlerInfo) { + var params = {}; + + // Soak up all the provided string/numbers + var numNames = names.length; + while (numNames--) { + + // Only use old params if the names match with the new handler + var oldParams = (oldHandlerInfo && name === oldHandlerInfo.name && oldHandlerInfo.params) || {}; + + var peek = objects[objects.length - 1]; + var paramName = names[numNames]; + if (isParam(peek)) { + params[paramName] = "" + objects.pop(); + } else { + // If we're here, this means only some of the params + // were string/number params, so try and use a param + // value from a previous handler. + if (oldParams.hasOwnProperty(paramName)) { + params[paramName] = oldParams[paramName]; + } else { + throw new Error("You didn't provide enough string/numeric parameters to satisfy all of the dynamic segments for route " + name); + } + } + } + + return handlerInfoFactory('param', { + name: name, + handler: handler, + params: params + }); + } + }); + }); +define("router/transition-intent/url-transition-intent", + ["../transition-intent","../transition-state","../handler-info/factory","../utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var TransitionIntent = __dependency1__["default"]; + var TransitionState = __dependency2__["default"]; + var handlerInfoFactory = __dependency3__["default"]; + var oCreate = __dependency4__.oCreate; + var merge = __dependency4__.merge; + var subclass = __dependency4__.subclass; + + __exports__["default"] = subclass(TransitionIntent, { + url: null, + + initialize: function(props) { + this.url = props.url; + }, + + applyToState: function(oldState, recognizer, getHandler) { + var newState = new TransitionState(); + + var results = recognizer.recognize(this.url), + queryParams = {}, + i, len; + + if (!results) { + throw new UnrecognizedURLError(this.url); + } + + var statesDiffer = false; + + for (i = 0, len = results.length; i < len; ++i) { + var result = results[i]; + var name = result.handler; + var handler = getHandler(name); + + if (handler.inaccessibleByURL) { + throw new UnrecognizedURLError(this.url); + } + + var newHandlerInfo = handlerInfoFactory('param', { + name: name, + handler: handler, + params: result.params + }); + + var oldHandlerInfo = oldState.handlerInfos[i]; + if (statesDiffer || newHandlerInfo.shouldSupercede(oldHandlerInfo)) { + statesDiffer = true; + newState.handlerInfos[i] = newHandlerInfo; + } else { + newState.handlerInfos[i] = oldHandlerInfo; + } + } + + merge(newState.queryParams, results.queryParams); + + return newState; + } + }); + + /** + Promise reject reasons passed to promise rejection + handlers for failed transitions. + */ + function UnrecognizedURLError(message) { + this.message = (message || "UnrecognizedURLError"); + this.name = "UnrecognizedURLError"; + } + }); +define("router/transition-state", + ["./handler-info","./utils","rsvp/promise","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var ResolvedHandlerInfo = __dependency1__.ResolvedHandlerInfo; + var forEach = __dependency2__.forEach; + var promiseLabel = __dependency2__.promiseLabel; + var callHook = __dependency2__.callHook; + var Promise = __dependency3__["default"]; + + function TransitionState(other) { + this.handlerInfos = []; + this.queryParams = {}; + this.params = {}; + } + + TransitionState.prototype = { + handlerInfos: null, + queryParams: null, + params: null, + + promiseLabel: function(label) { + var targetName = ''; + forEach(this.handlerInfos, function(handlerInfo) { + if (targetName !== '') { + targetName += '.'; + } + targetName += handlerInfo.name; + }); + return promiseLabel("'" + targetName + "': " + label); + }, + + resolve: function(shouldContinue, payload) { + var self = this; + // First, calculate params for this state. This is useful + // information to provide to the various route hooks. + var params = this.params; + forEach(this.handlerInfos, function(handlerInfo) { + params[handlerInfo.name] = handlerInfo.params || {}; + }); + + payload = payload || {}; + payload.resolveIndex = 0; + + var currentState = this; + var wasAborted = false; + + // The prelude RSVP.resolve() asyncs us into the promise land. + return Promise.resolve(null, this.promiseLabel("Start transition")) + .then(resolveOneHandlerInfo, null, this.promiseLabel('Resolve handler'))['catch'](handleError, this.promiseLabel('Handle error')); + + function innerShouldContinue() { + return Promise.resolve(shouldContinue(), currentState.promiseLabel("Check if should continue"))['catch'](function(reason) { + // We distinguish between errors that occurred + // during resolution (e.g. beforeModel/model/afterModel), + // and aborts due to a rejecting promise from shouldContinue(). + wasAborted = true; + return Promise.reject(reason); + }, currentState.promiseLabel("Handle abort")); + } + + function handleError(error) { + // This is the only possible + // reject value of TransitionState#resolve + var handlerInfos = currentState.handlerInfos; + var errorHandlerIndex = payload.resolveIndex >= handlerInfos.length ? + handlerInfos.length - 1 : payload.resolveIndex; + return Promise.reject({ + error: error, + handlerWithError: currentState.handlerInfos[errorHandlerIndex].handler, + wasAborted: wasAborted, + state: currentState + }); + } + + function proceed(resolvedHandlerInfo) { + var wasAlreadyResolved = currentState.handlerInfos[payload.resolveIndex].isResolved; + + // Swap the previously unresolved handlerInfo with + // the resolved handlerInfo + currentState.handlerInfos[payload.resolveIndex++] = resolvedHandlerInfo; + + if (!wasAlreadyResolved) { + // Call the redirect hook. The reason we call it here + // vs. afterModel is so that redirects into child + // routes don't re-run the model hooks for this + // already-resolved route. + var handler = resolvedHandlerInfo.handler; + callHook(handler, 'redirect', resolvedHandlerInfo.context, payload); + } + + // Proceed after ensuring that the redirect hook + // didn't abort this transition by transitioning elsewhere. + return innerShouldContinue().then(resolveOneHandlerInfo, null, currentState.promiseLabel('Resolve handler')); + } + + function resolveOneHandlerInfo() { + if (payload.resolveIndex === currentState.handlerInfos.length) { + // This is is the only possible + // fulfill value of TransitionState#resolve + return { + error: null, + state: currentState + }; + } + + var handlerInfo = currentState.handlerInfos[payload.resolveIndex]; + + return handlerInfo.resolve(innerShouldContinue, payload) + .then(proceed, null, currentState.promiseLabel('Proceed')); + } + } + }; + + __exports__["default"] = TransitionState; + }); +define("router/transition", + ["rsvp/promise","./handler-info","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var ResolvedHandlerInfo = __dependency2__.ResolvedHandlerInfo; + var trigger = __dependency3__.trigger; + var slice = __dependency3__.slice; + var log = __dependency3__.log; + var promiseLabel = __dependency3__.promiseLabel; + + /** + @private + + A Transition is a thennable (a promise-like object) that represents + an attempt to transition to another route. It can be aborted, either + explicitly via `abort` or by attempting another transition while a + previous one is still underway. An aborted transition can also + be `retry()`d later. + */ + function Transition(router, intent, state, error) { + var transition = this; + this.state = state || router.state; + this.intent = intent; + this.router = router; + this.data = this.intent && this.intent.data || {}; + this.resolvedModels = {}; + this.queryParams = {}; + + if (error) { + this.promise = Promise.reject(error); + return; + } + + if (state) { + this.params = state.params; + this.queryParams = state.queryParams; + this.handlerInfos = state.handlerInfos; + + var len = state.handlerInfos.length; + if (len) { + this.targetName = state.handlerInfos[len-1].name; + } + + for (var i = 0; i < len; ++i) { + var handlerInfo = state.handlerInfos[i]; + + // TODO: this all seems hacky + if (!handlerInfo.isResolved) { break; } + this.pivotHandler = handlerInfo.handler; + } + + this.sequence = Transition.currentSequence++; + this.promise = state.resolve(checkForAbort, this)['catch'](function(result) { + if (result.wasAborted || transition.isAborted) { + return Promise.reject(logAbort(transition)); + } else { + transition.trigger('error', result.error, transition, result.handlerWithError); + transition.abort(); + return Promise.reject(result.error); + } + }, promiseLabel('Handle Abort')); + } else { + this.promise = Promise.resolve(this.state); + this.params = {}; + } + + function checkForAbort() { + if (transition.isAborted) { + return Promise.reject(undefined, promiseLabel("Transition aborted - reject")); + } + } + } + + Transition.currentSequence = 0; + + Transition.prototype = { + targetName: null, + urlMethod: 'update', + intent: null, + params: null, + pivotHandler: null, + resolveIndex: 0, + handlerInfos: null, + resolvedModels: null, + isActive: true, + state: null, + queryParamsOnly: false, + + isTransition: true, + + isExiting: function(handler) { + var handlerInfos = this.handlerInfos; + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var handlerInfo = handlerInfos[i]; + if (handlerInfo.name === handler || handlerInfo.handler === handler) { + return false; + } + } + return true; + }, + + /** + @public + + The Transition's internal promise. Calling `.then` on this property + is that same as calling `.then` on the Transition object itself, but + this property is exposed for when you want to pass around a + Transition's promise, but not the Transition object itself, since + Transition object can be externally `abort`ed, while the promise + cannot. + */ + promise: null, + + /** + @public + + Custom state can be stored on a Transition's `data` object. + This can be useful for decorating a Transition within an earlier + hook and shared with a later hook. Properties set on `data` will + be copied to new transitions generated by calling `retry` on this + transition. + */ + data: null, + + /** + @public + + A standard promise hook that resolves if the transition + succeeds and rejects if it fails/redirects/aborts. + + Forwards to the internal `promise` property which you can + use in situations where you want to pass around a thennable, + but not the Transition itself. + + @param {Function} onFulfilled + @param {Function} onRejected + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + then: function(onFulfilled, onRejected, label) { + return this.promise.then(onFulfilled, onRejected, label); + }, + + /** + @public + + Forwards to the internal `promise` property which you can + use in situations where you want to pass around a thennable, + but not the Transition itself. + + @method catch + @param {Function} onRejection + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + "catch": function(onRejection, label) { + return this.promise["catch"](onRejection, label); + }, + + /** + @public + + Forwards to the internal `promise` property which you can + use in situations where you want to pass around a thennable, + but not the Transition itself. + + @method finally + @param {Function} callback + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + "finally": function(callback, label) { + return this.promise["finally"](callback, label); + }, + + /** + @public + + Aborts the Transition. Note you can also implicitly abort a transition + by initiating another transition while a previous one is underway. + */ + abort: function() { + if (this.isAborted) { return this; } + log(this.router, this.sequence, this.targetName + ": transition was aborted"); + this.intent.preTransitionState = this.router.state; + this.isAborted = true; + this.isActive = false; + this.router.activeTransition = null; + return this; + }, + + /** + @public + + Retries a previously-aborted transition (making sure to abort the + transition if it's still active). Returns a new transition that + represents the new attempt to transition. + */ + retry: function() { + // TODO: add tests for merged state retry()s + this.abort(); + return this.router.transitionByIntent(this.intent, false); + }, + + /** + @public + + Sets the URL-changing method to be employed at the end of a + successful transition. By default, a new Transition will just + use `updateURL`, but passing 'replace' to this method will + cause the URL to update using 'replaceWith' instead. Omitting + a parameter will disable the URL change, allowing for transitions + that don't update the URL at completion (this is also used for + handleURL, since the URL has already changed before the + transition took place). + + @param {String} method the type of URL-changing method to use + at the end of a transition. Accepted values are 'replace', + falsy values, or any other non-falsy value (which is + interpreted as an updateURL transition). + + @return {Transition} this transition + */ + method: function(method) { + this.urlMethod = method; + return this; + }, + + /** + @public + + Fires an event on the current list of resolved/resolving + handlers within this transition. Useful for firing events + on route hierarchies that haven't fully been entered yet. + + Note: This method is also aliased as `send` + + @param {Boolean} [ignoreFailure=false] a boolean specifying whether unhandled events throw an error + @param {String} name the name of the event to fire + */ + trigger: function (ignoreFailure) { + var args = slice.call(arguments); + if (typeof ignoreFailure === 'boolean') { + args.shift(); + } else { + // Throw errors on unhandled trigger events by default + ignoreFailure = false; + } + trigger(this.router, this.state.handlerInfos.slice(0, this.resolveIndex + 1), ignoreFailure, args); + }, + + /** + @public + + Transitions are aborted and their promises rejected + when redirects occur; this method returns a promise + that will follow any redirects that occur and fulfill + with the value fulfilled by any redirecting transitions + that occur. + + @return {Promise} a promise that fulfills with the same + value that the final redirecting transition fulfills with + */ + followRedirects: function() { + var router = this.router; + return this.promise['catch'](function(reason) { + if (router.activeTransition) { + return router.activeTransition.followRedirects(); + } + return Promise.reject(reason); + }); + }, + + toString: function() { + return "Transition (sequence " + this.sequence + ")"; + }, + + /** + @private + */ + log: function(message) { + log(this.router, this.sequence, message); + } + }; + + // Alias 'trigger' as 'send' + Transition.prototype.send = Transition.prototype.trigger; + + /** + @private + + Logs and returns a TransitionAborted error. + */ + function logAbort(transition) { + log(transition.router, transition.sequence, "detected abort."); + return new TransitionAborted(); + } + + function TransitionAborted(message) { + this.message = (message || "TransitionAborted"); + this.name = "TransitionAborted"; + } + + __exports__.Transition = Transition; + __exports__.logAbort = logAbort; + __exports__.TransitionAborted = TransitionAborted; + }); +define("router/utils", + ["exports"], + function(__exports__) { + "use strict"; + var slice = Array.prototype.slice; + + var _isArray; + if (!Array.isArray) { + _isArray = function (x) { + return Object.prototype.toString.call(x) === "[object Array]"; + }; + } else { + _isArray = Array.isArray; + } + + var isArray = _isArray; + __exports__.isArray = isArray; + function merge(hash, other) { + for (var prop in other) { + if (other.hasOwnProperty(prop)) { hash[prop] = other[prop]; } + } + } + + var oCreate = Object.create || function(proto) { + function F() {} + F.prototype = proto; + return new F(); + }; + __exports__.oCreate = oCreate; + /** + @private + + Extracts query params from the end of an array + **/ + function extractQueryParams(array) { + var len = (array && array.length), head, queryParams; + + if(len && len > 0 && array[len - 1] && array[len - 1].hasOwnProperty('queryParams')) { + queryParams = array[len - 1].queryParams; + head = slice.call(array, 0, len - 1); + return [head, queryParams]; + } else { + return [array, null]; + } + } + + __exports__.extractQueryParams = extractQueryParams;/** + @private + + Coerces query param properties and array elements into strings. + **/ + function coerceQueryParamsToString(queryParams) { + for (var key in queryParams) { + if (typeof queryParams[key] === 'number') { + queryParams[key] = '' + queryParams[key]; + } else if (isArray(queryParams[key])) { + for (var i = 0, l = queryParams[key].length; i < l; i++) { + queryParams[key][i] = '' + queryParams[key][i]; + } + } + } + } + /** + @private + */ + function log(router, sequence, msg) { + if (!router.log) { return; } + + if (arguments.length === 3) { + router.log("Transition #" + sequence + ": " + msg); + } else { + msg = sequence; + router.log(msg); + } + } + + __exports__.log = log;function bind(context, fn) { + var boundArgs = arguments; + return function(value) { + var args = slice.call(boundArgs, 2); + args.push(value); + return fn.apply(context, args); + }; + } + + __exports__.bind = bind;function isParam(object) { + return (typeof object === "string" || object instanceof String || typeof object === "number" || object instanceof Number); + } + + + function forEach(array, callback) { + for (var i=0, l=array.length; i=0; i--) { + var handlerInfo = handlerInfos[i], + handler = handlerInfo.handler; + + if (handler.events && handler.events[name]) { + if (handler.events[name].apply(handler, args) === true) { + eventWasHandled = true; + } else { + return; + } + } + } + + if (!eventWasHandled && !ignoreFailure) { + throw new Error("Nothing handled the event '" + name + "'."); + } + } + + __exports__.trigger = trigger;function getChangelist(oldObject, newObject) { + var key; + var results = { + all: {}, + changed: {}, + removed: {} + }; + + merge(results.all, newObject); + + var didChange = false; + coerceQueryParamsToString(oldObject); + coerceQueryParamsToString(newObject); + + // Calculate removals + for (key in oldObject) { + if (oldObject.hasOwnProperty(key)) { + if (!newObject.hasOwnProperty(key)) { + didChange = true; + results.removed[key] = oldObject[key]; + } + } + } + + // Calculate changes + for (key in newObject) { + if (newObject.hasOwnProperty(key)) { + if (isArray(oldObject[key]) && isArray(newObject[key])) { + if (oldObject[key].length !== newObject[key].length) { + results.changed[key] = newObject[key]; + didChange = true; + } else { + for (var i = 0, l = oldObject[key].length; i < l; i++) { + if (oldObject[key][i] !== newObject[key][i]) { + results.changed[key] = newObject[key]; + didChange = true; + } + } + } + } + else { + if (oldObject[key] !== newObject[key]) { + results.changed[key] = newObject[key]; + didChange = true; + } + } + } + } + + return didChange && results; + } + + __exports__.getChangelist = getChangelist;function promiseLabel(label) { + return 'Router: ' + label; + } + + __exports__.promiseLabel = promiseLabel;function subclass(parentConstructor, proto) { + function C(props) { + parentConstructor.call(this, props || {}); + } + C.prototype = oCreate(parentConstructor.prototype); + merge(C.prototype, proto); + return C; + } + + __exports__.subclass = subclass;function resolveHook(obj, hookName) { + if (!obj) { return; } + var underscored = "_" + hookName; + return obj[underscored] && underscored || + obj[hookName] && hookName; + } + + function callHook(obj, hookName) { + var args = slice.call(arguments, 2); + return applyHook(obj, hookName, args); + } + + function applyHook(obj, _hookName, args) { + var hookName = resolveHook(obj, _hookName); + if (hookName) { + return obj[hookName].apply(obj, args); + } + } + + __exports__.merge = merge; + __exports__.slice = slice; + __exports__.isParam = isParam; + __exports__.coerceQueryParamsToString = coerceQueryParamsToString; + __exports__.callHook = callHook; + __exports__.resolveHook = resolveHook; + __exports__.applyHook = applyHook; + }); +define("router", + ["./router/router","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Router = __dependency1__["default"]; + + __exports__["default"] = Router; + }); + +define("rsvp", + ["./rsvp/promise","./rsvp/events","./rsvp/node","./rsvp/all","./rsvp/all-settled","./rsvp/race","./rsvp/hash","./rsvp/hash-settled","./rsvp/rethrow","./rsvp/defer","./rsvp/config","./rsvp/map","./rsvp/resolve","./rsvp/reject","./rsvp/filter","./rsvp/asap","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var EventTarget = __dependency2__["default"]; + var denodeify = __dependency3__["default"]; + var all = __dependency4__["default"]; + var allSettled = __dependency5__["default"]; + var race = __dependency6__["default"]; + var hash = __dependency7__["default"]; + var hashSettled = __dependency8__["default"]; + var rethrow = __dependency9__["default"]; + var defer = __dependency10__["default"]; + var config = __dependency11__.config; + var configure = __dependency11__.configure; + var map = __dependency12__["default"]; + var resolve = __dependency13__["default"]; + var reject = __dependency14__["default"]; + var filter = __dependency15__["default"]; + var asap = __dependency16__["default"]; + + config.async = asap; // default async is asap; + var cast = resolve; + function async(callback, arg) { + config.async(callback, arg); + } + + function on() { + config.on.apply(config, arguments); + } + + function off() { + config.off.apply(config, arguments); + } + + // Set up instrumentation through `window.__PROMISE_INTRUMENTATION__` + if (typeof window !== 'undefined' && typeof window['__PROMISE_INSTRUMENTATION__'] === 'object') { + var callbacks = window['__PROMISE_INSTRUMENTATION__']; + configure('instrument', true); + for (var eventName in callbacks) { + if (callbacks.hasOwnProperty(eventName)) { + on(eventName, callbacks[eventName]); + } + } + } + + __exports__.cast = cast; + __exports__.Promise = Promise; + __exports__.EventTarget = EventTarget; + __exports__.all = all; + __exports__.allSettled = allSettled; + __exports__.race = race; + __exports__.hash = hash; + __exports__.hashSettled = hashSettled; + __exports__.rethrow = rethrow; + __exports__.defer = defer; + __exports__.denodeify = denodeify; + __exports__.configure = configure; + __exports__.on = on; + __exports__.off = off; + __exports__.resolve = resolve; + __exports__.reject = reject; + __exports__.async = async; + __exports__.map = map; + __exports__.filter = filter; + }); +define("rsvp.umd", + ["./rsvp"], + function(__dependency1__) { + "use strict"; + var Promise = __dependency1__.Promise; + var allSettled = __dependency1__.allSettled; + var hash = __dependency1__.hash; + var hashSettled = __dependency1__.hashSettled; + var denodeify = __dependency1__.denodeify; + var on = __dependency1__.on; + var off = __dependency1__.off; + var map = __dependency1__.map; + var filter = __dependency1__.filter; + var resolve = __dependency1__.resolve; + var reject = __dependency1__.reject; + var rethrow = __dependency1__.rethrow; + var all = __dependency1__.all; + var defer = __dependency1__.defer; + var EventTarget = __dependency1__.EventTarget; + var configure = __dependency1__.configure; + var race = __dependency1__.race; + var async = __dependency1__.async; + + var RSVP = { + 'race': race, + 'Promise': Promise, + 'allSettled': allSettled, + 'hash': hash, + 'hashSettled': hashSettled, + 'denodeify': denodeify, + 'on': on, + 'off': off, + 'map': map, + 'filter': filter, + 'resolve': resolve, + 'reject': reject, + 'all': all, + 'rethrow': rethrow, + 'defer': defer, + 'EventTarget': EventTarget, + 'configure': configure, + 'async': async + }; + + /* global define:true module:true window: true */ + if (typeof define === 'function' && define.amd) { + define(function() { return RSVP; }); + } else if (typeof module !== 'undefined' && module.exports) { + module.exports = RSVP; + } else if (typeof this !== 'undefined') { + this['RSVP'] = RSVP; + } + }); +define("rsvp/-internal", + ["./utils","./instrument","./config","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var objectOrFunction = __dependency1__.objectOrFunction; + var isFunction = __dependency1__.isFunction; + + var instrument = __dependency2__["default"]; + + var config = __dependency3__.config; + + function noop() {} + + var PENDING = void 0; + var FULFILLED = 1; + var REJECTED = 2; + + var GET_THEN_ERROR = new ErrorObject(); + + function getThen(promise) { + try { + return promise.then; + } catch(error) { + GET_THEN_ERROR.error = error; + return GET_THEN_ERROR; + } + } + + function tryThen(then, value, fulfillmentHandler, rejectionHandler) { + try { + then.call(value, fulfillmentHandler, rejectionHandler); + } catch(e) { + return e; + } + } + + function handleForeignThenable(promise, thenable, then) { + config.async(function(promise) { + var sealed = false; + var error = tryThen(then, thenable, function(value) { + if (sealed) { return; } + sealed = true; + if (thenable !== value) { + resolve(promise, value); + } else { + fulfill(promise, value); + } + }, function(reason) { + if (sealed) { return; } + sealed = true; + + reject(promise, reason); + }, 'Settle: ' + (promise._label || ' unknown promise')); + + if (!sealed && error) { + sealed = true; + reject(promise, error); + } + }, promise); + } + + function handleOwnThenable(promise, thenable) { + if (thenable._state === FULFILLED) { + fulfill(promise, thenable._result); + } else if (promise._state === REJECTED) { + reject(promise, thenable._result); + } else { + subscribe(thenable, undefined, function(value) { + if (thenable !== value) { + resolve(promise, value); + } else { + fulfill(promise, value); + } + }, function(reason) { + reject(promise, reason); + }); + } + } + + function handleMaybeThenable(promise, maybeThenable) { + if (maybeThenable.constructor === promise.constructor) { + handleOwnThenable(promise, maybeThenable); + } else { + var then = getThen(maybeThenable); + + if (then === GET_THEN_ERROR) { + reject(promise, GET_THEN_ERROR.error); + } else if (then === undefined) { + fulfill(promise, maybeThenable); + } else if (isFunction(then)) { + handleForeignThenable(promise, maybeThenable, then); + } else { + fulfill(promise, maybeThenable); + } + } + } + + function resolve(promise, value) { + if (promise === value) { + fulfill(promise, value); + } else if (objectOrFunction(value)) { + handleMaybeThenable(promise, value); + } else { + fulfill(promise, value); + } + } + + function publishRejection(promise) { + if (promise._onerror) { + promise._onerror(promise._result); + } + + publish(promise); + } + + function fulfill(promise, value) { + if (promise._state !== PENDING) { return; } + + promise._result = value; + promise._state = FULFILLED; + + if (promise._subscribers.length === 0) { + if (config.instrument) { + instrument('fulfilled', promise); + } + } else { + config.async(publish, promise); + } + } + + function reject(promise, reason) { + if (promise._state !== PENDING) { return; } + promise._state = REJECTED; + promise._result = reason; + + config.async(publishRejection, promise); + } + + function subscribe(parent, child, onFulfillment, onRejection) { + var subscribers = parent._subscribers; + var length = subscribers.length; + + parent._onerror = null; + + subscribers[length] = child; + subscribers[length + FULFILLED] = onFulfillment; + subscribers[length + REJECTED] = onRejection; + + if (length === 0 && parent._state) { + config.async(publish, parent); + } + } + + function publish(promise) { + var subscribers = promise._subscribers; + var settled = promise._state; + + if (config.instrument) { + instrument(settled === FULFILLED ? 'fulfilled' : 'rejected', promise); + } + + if (subscribers.length === 0) { return; } + + var child, callback, detail = promise._result; + + for (var i = 0; i < subscribers.length; i += 3) { + child = subscribers[i]; + callback = subscribers[i + settled]; + + if (child) { + invokeCallback(settled, child, callback, detail); + } else { + callback(detail); + } + } + + promise._subscribers.length = 0; + } + + function ErrorObject() { + this.error = null; + } + + var TRY_CATCH_ERROR = new ErrorObject(); + + function tryCatch(callback, detail) { + try { + return callback(detail); + } catch(e) { + TRY_CATCH_ERROR.error = e; + return TRY_CATCH_ERROR; + } + } + + function invokeCallback(settled, promise, callback, detail) { + var hasCallback = isFunction(callback), + value, error, succeeded, failed; + + if (hasCallback) { + value = tryCatch(callback, detail); + + if (value === TRY_CATCH_ERROR) { + failed = true; + error = value.error; + value = null; + } else { + succeeded = true; + } + + if (promise === value) { + reject(promise, new TypeError('A promises callback cannot return that same promise.')); + return; + } + + } else { + value = detail; + succeeded = true; + } + + if (promise._state !== PENDING) { + // noop + } else if (hasCallback && succeeded) { + resolve(promise, value); + } else if (failed) { + reject(promise, error); + } else if (settled === FULFILLED) { + fulfill(promise, value); + } else if (settled === REJECTED) { + reject(promise, value); + } + } + + function initializePromise(promise, resolver) { + try { + resolver(function resolvePromise(value){ + resolve(promise, value); + }, function rejectPromise(reason) { + reject(promise, reason); + }); + } catch(e) { + reject(promise, e); + } + } + + __exports__.noop = noop; + __exports__.resolve = resolve; + __exports__.reject = reject; + __exports__.fulfill = fulfill; + __exports__.subscribe = subscribe; + __exports__.publish = publish; + __exports__.publishRejection = publishRejection; + __exports__.initializePromise = initializePromise; + __exports__.invokeCallback = invokeCallback; + __exports__.FULFILLED = FULFILLED; + __exports__.REJECTED = REJECTED; + __exports__.PENDING = PENDING; + }); +define("rsvp/all-settled", + ["./enumerator","./promise","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Enumerator = __dependency1__["default"]; + var makeSettledResult = __dependency1__.makeSettledResult; + var Promise = __dependency2__["default"]; + var o_create = __dependency3__.o_create; + + function AllSettled(Constructor, entries, label) { + this._superConstructor(Constructor, entries, false /* don't abort on reject */, label); + } + + AllSettled.prototype = o_create(Enumerator.prototype); + AllSettled.prototype._superConstructor = Enumerator; + AllSettled.prototype._makeResult = makeSettledResult; + AllSettled.prototype._validationError = function() { + return new Error('allSettled must be called with an array'); + }; + + /** + `RSVP.allSettled` is similar to `RSVP.all`, but instead of implementing + a fail-fast method, it waits until all the promises have returned and + shows you all the results. This is useful if you want to handle multiple + promises' failure states together as a set. + + Returns a promise that is fulfilled when all the given promises have been + settled. The return promise is fulfilled with an array of the states of + the promises passed into the `promises` array argument. + + Each state object will either indicate fulfillment or rejection, and + provide the corresponding value or reason. The states will take one of + the following formats: + + ```javascript + { state: 'fulfilled', value: value } + or + { state: 'rejected', reason: reason } + ``` + + Example: + + ```javascript + var promise1 = RSVP.Promise.resolve(1); + var promise2 = RSVP.Promise.reject(new Error('2')); + var promise3 = RSVP.Promise.reject(new Error('3')); + var promises = [ promise1, promise2, promise3 ]; + + RSVP.allSettled(promises).then(function(array){ + // array == [ + // { state: 'fulfilled', value: 1 }, + // { state: 'rejected', reason: Error }, + // { state: 'rejected', reason: Error } + // ] + // Note that for the second item, reason.message will be '2', and for the + // third item, reason.message will be '3'. + }, function(error) { + // Not run. (This block would only be called if allSettled had failed, + // for instance if passed an incorrect argument type.) + }); + ``` + + @method allSettled + @static + @for RSVP + @param {Array} promises + @param {String} label - optional string that describes the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled with an array of the settled + states of the constituent promises. + */ + + __exports__["default"] = function allSettled(entries, label) { + return new AllSettled(Promise, entries, label).promise; + } + }); +define("rsvp/all", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + This is a convenient alias for `RSVP.Promise.all`. + + @method all + @static + @for RSVP + @param {Array} array Array of promises. + @param {String} label An optional label. This is useful + for tooling. + */ + __exports__["default"] = function all(array, label) { + return Promise.all(array, label); + } + }); +define("rsvp/asap", + ["exports"], + function(__exports__) { + "use strict"; + var len = 0; + + __exports__["default"] = function asap(callback, arg) { + queue[len] = callback; + queue[len + 1] = arg; + len += 2; + if (len === 2) { + // If len is 1, that means that we need to schedule an async flush. + // If additional callbacks are queued before the queue is flushed, they + // will be processed by this flush that we are scheduling. + scheduleFlush(); + } + } + + var browserGlobal = (typeof window !== 'undefined') ? window : {}; + var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver; + + // test for web worker but not in IE10 + var isWorker = typeof Uint8ClampedArray !== 'undefined' && + typeof importScripts !== 'undefined' && + typeof MessageChannel !== 'undefined'; + + // node + function useNextTick() { + return function() { + process.nextTick(flush); + }; + } + + function useMutationObserver() { + var iterations = 0; + var observer = new BrowserMutationObserver(flush); + var node = document.createTextNode(''); + observer.observe(node, { characterData: true }); + + return function() { + node.data = (iterations = ++iterations % 2); + }; + } + + // web worker + function useMessageChannel() { + var channel = new MessageChannel(); + channel.port1.onmessage = flush; + return function () { + channel.port2.postMessage(0); + }; + } + + function useSetTimeout() { + return function() { + setTimeout(flush, 1); + }; + } + + var queue = new Array(1000); + function flush() { + for (var i = 0; i < len; i+=2) { + var callback = queue[i]; + var arg = queue[i+1]; + + callback(arg); + + queue[i] = undefined; + queue[i+1] = undefined; + } + + len = 0; + } + + var scheduleFlush; + + // Decide what async method to use to triggering processing of queued callbacks: + if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') { + scheduleFlush = useNextTick(); + } else if (BrowserMutationObserver) { + scheduleFlush = useMutationObserver(); + } else if (isWorker) { + scheduleFlush = useMessageChannel(); + } else { + scheduleFlush = useSetTimeout(); + } + }); +define("rsvp/config", + ["./events","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var EventTarget = __dependency1__["default"]; + + var config = { + instrument: false + }; + + EventTarget.mixin(config); + + function configure(name, value) { + if (name === 'onerror') { + // handle for legacy users that expect the actual + // error to be passed to their function added via + // `RSVP.configure('onerror', someFunctionHere);` + config.on('error', value); + return; + } + + if (arguments.length === 2) { + config[name] = value; + } else { + return config[name]; + } + } + + __exports__.config = config; + __exports__.configure = configure; + }); +define("rsvp/defer", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + `RSVP.defer` returns an object similar to jQuery's `$.Deferred`. + `RSVP.defer` should be used when porting over code reliant on `$.Deferred`'s + interface. New code should use the `RSVP.Promise` constructor instead. + + The object returned from `RSVP.defer` is a plain object with three properties: + + * promise - an `RSVP.Promise`. + * reject - a function that causes the `promise` property on this object to + become rejected + * resolve - a function that causes the `promise` property on this object to + become fulfilled. + + Example: + + ```javascript + var deferred = RSVP.defer(); + + deferred.resolve("Success!"); + + defered.promise.then(function(value){ + // value here is "Success!" + }); + ``` + + @method defer + @static + @for RSVP + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Object} + */ + + __exports__["default"] = function defer(label) { + var deferred = { }; + + deferred.promise = new Promise(function(resolve, reject) { + deferred.resolve = resolve; + deferred.reject = reject; + }, label); + + return deferred; + } + }); +define("rsvp/enumerator", + ["./utils","./-internal","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var isArray = __dependency1__.isArray; + var isMaybeThenable = __dependency1__.isMaybeThenable; + + var noop = __dependency2__.noop; + var reject = __dependency2__.reject; + var fulfill = __dependency2__.fulfill; + var subscribe = __dependency2__.subscribe; + var FULFILLED = __dependency2__.FULFILLED; + var REJECTED = __dependency2__.REJECTED; + var PENDING = __dependency2__.PENDING; + + function makeSettledResult(state, position, value) { + if (state === FULFILLED) { + return { + state: 'fulfilled', + value: value + }; + } else { + return { + state: 'rejected', + reason: value + }; + } + } + + __exports__.makeSettledResult = makeSettledResult;function Enumerator(Constructor, input, abortOnReject, label) { + this._instanceConstructor = Constructor; + this.promise = new Constructor(noop, label); + this._abortOnReject = abortOnReject; + + if (this._validateInput(input)) { + this._input = input; + this.length = input.length; + this._remaining = input.length; + + this._init(); + + if (this.length === 0) { + fulfill(this.promise, this._result); + } else { + this.length = this.length || 0; + this._enumerate(); + if (this._remaining === 0) { + fulfill(this.promise, this._result); + } + } + } else { + reject(this.promise, this._validationError()); + } + } + + Enumerator.prototype._validateInput = function(input) { + return isArray(input); + }; + + Enumerator.prototype._validationError = function() { + return new Error('Array Methods must be provided an Array'); + }; + + Enumerator.prototype._init = function() { + this._result = new Array(this.length); + }; + + __exports__["default"] = Enumerator; + + Enumerator.prototype._enumerate = function() { + var length = this.length; + var promise = this.promise; + var input = this._input; + + for (var i = 0; promise._state === PENDING && i < length; i++) { + this._eachEntry(input[i], i); + } + }; + + Enumerator.prototype._eachEntry = function(entry, i) { + var c = this._instanceConstructor; + if (isMaybeThenable(entry)) { + if (entry.constructor === c && entry._state !== PENDING) { + entry._onerror = null; + this._settledAt(entry._state, i, entry._result); + } else { + this._willSettleAt(c.resolve(entry), i); + } + } else { + this._remaining--; + this._result[i] = this._makeResult(FULFILLED, i, entry); + } + }; + + Enumerator.prototype._settledAt = function(state, i, value) { + var promise = this.promise; + + if (promise._state === PENDING) { + this._remaining--; + + if (this._abortOnReject && state === REJECTED) { + reject(promise, value); + } else { + this._result[i] = this._makeResult(state, i, value); + } + } + + if (this._remaining === 0) { + fulfill(promise, this._result); + } + }; + + Enumerator.prototype._makeResult = function(state, i, value) { + return value; + }; + + Enumerator.prototype._willSettleAt = function(promise, i) { + var enumerator = this; + + subscribe(promise, undefined, function(value) { + enumerator._settledAt(FULFILLED, i, value); + }, function(reason) { + enumerator._settledAt(REJECTED, i, reason); + }); + }; + }); +define("rsvp/events", + ["exports"], + function(__exports__) { + "use strict"; + function indexOf(callbacks, callback) { + for (var i=0, l=callbacks.length; i 1; + }; + + RSVP.filter(promises, filterFn).then(function(result){ + // result is [ 2, 3 ] + }); + ``` + + If any of the `promises` given to `RSVP.filter` are rejected, the first promise + that is rejected will be given as an argument to the returned promise's + rejection handler. For example: + + ```javascript + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.reject(new Error('2')); + var promise3 = RSVP.reject(new Error('3')); + var promises = [ promise1, promise2, promise3 ]; + + var filterFn = function(item){ + return item > 1; + }; + + RSVP.filter(promises, filterFn).then(function(array){ + // Code here never runs because there are rejected promises! + }, function(reason) { + // reason.message === '2' + }); + ``` + + `RSVP.filter` will also wait for any promises returned from `filterFn`. + For instance, you may want to fetch a list of users then return a subset + of those users based on some asynchronous operation: + + ```javascript + + var alice = { name: 'alice' }; + var bob = { name: 'bob' }; + var users = [ alice, bob ]; + + var promises = users.map(function(user){ + return RSVP.resolve(user); + }); + + var filterFn = function(user){ + // Here, Alice has permissions to create a blog post, but Bob does not. + return getPrivilegesForUser(user).then(function(privs){ + return privs.can_create_blog_post === true; + }); + }; + RSVP.filter(promises, filterFn).then(function(users){ + // true, because the server told us only Alice can create a blog post. + users.length === 1; + // false, because Alice is the only user present in `users` + users[0] === bob; + }); + ``` + + @method filter + @static + @for RSVP + @param {Array} promises + @param {Function} filterFn - function to be called on each resolved value to + filter the final results. + @param {String} label optional string describing the promise. Useful for + tooling. + @return {Promise} + */ + __exports__["default"] = function filter(promises, filterFn, label) { + return Promise.all(promises, label).then(function(values) { + if (!isFunction(filterFn)) { + throw new TypeError("You must pass a function as filter's second argument."); + } + + var length = values.length; + var filtered = new Array(length); + + for (var i = 0; i < length; i++) { + filtered[i] = filterFn(values[i]); + } + + return Promise.all(filtered, label).then(function(filtered) { + var results = new Array(length); + var newLength = 0; + + for (var i = 0; i < length; i++) { + if (filtered[i]) { + results[newLength] = values[i]; + newLength++; + } + } + + results.length = newLength; + + return results; + }); + }); + } + }); +define("rsvp/hash-settled", + ["./promise","./enumerator","./promise-hash","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var makeSettledResult = __dependency2__.makeSettledResult; + var PromiseHash = __dependency3__["default"]; + var Enumerator = __dependency2__["default"]; + var o_create = __dependency4__.o_create; + + function HashSettled(Constructor, object, label) { + this._superConstructor(Constructor, object, false, label); + } + + HashSettled.prototype = o_create(PromiseHash.prototype); + HashSettled.prototype._superConstructor = Enumerator; + HashSettled.prototype._makeResult = makeSettledResult; + + HashSettled.prototype._validationError = function() { + return new Error('hashSettled must be called with an object'); + }; + + /** + `RSVP.hashSettled` is similar to `RSVP.allSettled`, but takes an object + instead of an array for its `promises` argument. + + Unlike `RSVP.all` or `RSVP.hash`, which implement a fail-fast method, + but like `RSVP.allSettled`, `hashSettled` waits until all the + constituent promises have returned and then shows you all the results + with their states and values/reasons. This is useful if you want to + handle multiple promises' failure states together as a set. + + Returns a promise that is fulfilled when all the given promises have been + settled, or rejected if the passed parameters are invalid. + + The returned promise is fulfilled with a hash that has the same key names as + the `promises` object argument. If any of the values in the object are not + promises, they will be copied over to the fulfilled object and marked with state + 'fulfilled'. + + Example: + + ```javascript + var promises = { + myPromise: RSVP.Promise.resolve(1), + yourPromise: RSVP.Promise.resolve(2), + theirPromise: RSVP.Promise.resolve(3), + notAPromise: 4 + }; + + RSVP.hashSettled(promises).then(function(hash){ + // hash here is an object that looks like: + // { + // myPromise: { state: 'fulfilled', value: 1 }, + // yourPromise: { state: 'fulfilled', value: 2 }, + // theirPromise: { state: 'fulfilled', value: 3 }, + // notAPromise: { state: 'fulfilled', value: 4 } + // } + }); + ``` + + If any of the `promises` given to `RSVP.hash` are rejected, the state will + be set to 'rejected' and the reason for rejection provided. + + Example: + + ```javascript + var promises = { + myPromise: RSVP.Promise.resolve(1), + rejectedPromise: RSVP.Promise.reject(new Error('rejection')), + anotherRejectedPromise: RSVP.Promise.reject(new Error('more rejection')), + }; + + RSVP.hashSettled(promises).then(function(hash){ + // hash here is an object that looks like: + // { + // myPromise: { state: 'fulfilled', value: 1 }, + // rejectedPromise: { state: 'rejected', reason: Error }, + // anotherRejectedPromise: { state: 'rejected', reason: Error }, + // } + // Note that for rejectedPromise, reason.message == 'rejection', + // and for anotherRejectedPromise, reason.message == 'more rejection'. + }); + ``` + + An important note: `RSVP.hashSettled` is intended for plain JavaScript objects that + are just a set of keys and values. `RSVP.hashSettled` will NOT preserve prototype + chains. + + Example: + + ```javascript + function MyConstructor(){ + this.example = RSVP.Promise.resolve('Example'); + } + + MyConstructor.prototype = { + protoProperty: RSVP.Promise.resolve('Proto Property') + }; + + var myObject = new MyConstructor(); + + RSVP.hashSettled(myObject).then(function(hash){ + // protoProperty will not be present, instead you will just have an + // object that looks like: + // { + // example: { state: 'fulfilled', value: 'Example' } + // } + // + // hash.hasOwnProperty('protoProperty'); // false + // 'undefined' === typeof hash.protoProperty + }); + ``` + + @method hashSettled + @for RSVP + @param {Object} promises + @param {String} label optional string that describes the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled when when all properties of `promises` + have been settled. + @static + */ + __exports__["default"] = function hashSettled(object, label) { + return new HashSettled(Promise, object, label).promise; + } + }); +define("rsvp/hash", + ["./promise","./promise-hash","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var PromiseHash = __dependency2__["default"]; + + /** + `RSVP.hash` is similar to `RSVP.all`, but takes an object instead of an array + for its `promises` argument. + + Returns a promise that is fulfilled when all the given promises have been + fulfilled, or rejected if any of them become rejected. The returned promise + is fulfilled with a hash that has the same key names as the `promises` object + argument. If any of the values in the object are not promises, they will + simply be copied over to the fulfilled object. + + Example: + + ```javascript + var promises = { + myPromise: RSVP.resolve(1), + yourPromise: RSVP.resolve(2), + theirPromise: RSVP.resolve(3), + notAPromise: 4 + }; + + RSVP.hash(promises).then(function(hash){ + // hash here is an object that looks like: + // { + // myPromise: 1, + // yourPromise: 2, + // theirPromise: 3, + // notAPromise: 4 + // } + }); + ```` + + If any of the `promises` given to `RSVP.hash` are rejected, the first promise + that is rejected will be given as the reason to the rejection handler. + + Example: + + ```javascript + var promises = { + myPromise: RSVP.resolve(1), + rejectedPromise: RSVP.reject(new Error('rejectedPromise')), + anotherRejectedPromise: RSVP.reject(new Error('anotherRejectedPromise')), + }; + + RSVP.hash(promises).then(function(hash){ + // Code here never runs because there are rejected promises! + }, function(reason) { + // reason.message === 'rejectedPromise' + }); + ``` + + An important note: `RSVP.hash` is intended for plain JavaScript objects that + are just a set of keys and values. `RSVP.hash` will NOT preserve prototype + chains. + + Example: + + ```javascript + function MyConstructor(){ + this.example = RSVP.resolve('Example'); + } + + MyConstructor.prototype = { + protoProperty: RSVP.resolve('Proto Property') + }; + + var myObject = new MyConstructor(); + + RSVP.hash(myObject).then(function(hash){ + // protoProperty will not be present, instead you will just have an + // object that looks like: + // { + // example: 'Example' + // } + // + // hash.hasOwnProperty('protoProperty'); // false + // 'undefined' === typeof hash.protoProperty + }); + ``` + + @method hash + @static + @for RSVP + @param {Object} promises + @param {String} label optional string that describes the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled when all properties of `promises` + have been fulfilled, or rejected if any of them become rejected. + */ + __exports__["default"] = function hash(object, label) { + return new PromiseHash(Promise, object, label).promise; + } + }); +define("rsvp/instrument", + ["./config","./utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var config = __dependency1__.config; + var now = __dependency2__.now; + + var queue = []; + + __exports__["default"] = function instrument(eventName, promise, child) { + if (1 === queue.push({ + name: eventName, + payload: { + guid: promise._guidKey + promise._id, + eventName: eventName, + detail: promise._result, + childGuid: child && promise._guidKey + child._id, + label: promise._label, + timeStamp: now(), + stack: new Error(promise._label).stack + }})) { + + setTimeout(function() { + var entry; + for (var i = 0; i < queue.length; i++) { + entry = queue[i]; + config.trigger(entry.name, entry.payload); + } + queue.length = 0; + }, 50); + } + } + }); +define("rsvp/map", + ["./promise","./utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var isFunction = __dependency2__.isFunction; + + /** + `RSVP.map` is similar to JavaScript's native `map` method, except that it + waits for all promises to become fulfilled before running the `mapFn` on + each item in given to `promises`. `RSVP.map` returns a promise that will + become fulfilled with the result of running `mapFn` on the values the promises + become fulfilled with. + + For example: + + ```javascript + + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.resolve(2); + var promise3 = RSVP.resolve(3); + var promises = [ promise1, promise2, promise3 ]; + + var mapFn = function(item){ + return item + 1; + }; + + RSVP.map(promises, mapFn).then(function(result){ + // result is [ 2, 3, 4 ] + }); + ``` + + If any of the `promises` given to `RSVP.map` are rejected, the first promise + that is rejected will be given as an argument to the returned promise's + rejection handler. For example: + + ```javascript + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.reject(new Error('2')); + var promise3 = RSVP.reject(new Error('3')); + var promises = [ promise1, promise2, promise3 ]; + + var mapFn = function(item){ + return item + 1; + }; + + RSVP.map(promises, mapFn).then(function(array){ + // Code here never runs because there are rejected promises! + }, function(reason) { + // reason.message === '2' + }); + ``` + + `RSVP.map` will also wait if a promise is returned from `mapFn`. For example, + say you want to get all comments from a set of blog posts, but you need + the blog posts first because they contain a url to those comments. + + ```javscript + + var mapFn = function(blogPost){ + // getComments does some ajax and returns an RSVP.Promise that is fulfilled + // with some comments data + return getComments(blogPost.comments_url); + }; + + // getBlogPosts does some ajax and returns an RSVP.Promise that is fulfilled + // with some blog post data + RSVP.map(getBlogPosts(), mapFn).then(function(comments){ + // comments is the result of asking the server for the comments + // of all blog posts returned from getBlogPosts() + }); + ``` + + @method map + @static + @for RSVP + @param {Array} promises + @param {Function} mapFn function to be called on each fulfilled promise. + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled with the result of calling + `mapFn` on each fulfilled promise or value when they become fulfilled. + The promise will be rejected if any of the given `promises` become rejected. + @static + */ + __exports__["default"] = function map(promises, mapFn, label) { + return Promise.all(promises, label).then(function(values) { + if (!isFunction(mapFn)) { + throw new TypeError("You must pass a function as map's second argument."); + } + + var length = values.length; + var results = new Array(length); + + for (var i = 0; i < length; i++) { + results[i] = mapFn(values[i]); + } + + return Promise.all(results, label); + }); + } + }); +define("rsvp/node", + ["./promise","./-internal","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var noop = __dependency2__.noop; + var resolve = __dependency2__.resolve; + var reject = __dependency2__.reject; + var isArray = __dependency3__.isArray; + + function Result() { + this.value = undefined; + } + + var ERROR = new Result(); + var GET_THEN_ERROR = new Result(); + + function getThen(obj) { + try { + return obj.then; + } catch(error) { + ERROR.value= error; + return ERROR; + } + } + + + function tryApply(f, s, a) { + try { + f.apply(s, a); + } catch(error) { + ERROR.value = error; + return ERROR; + } + } + + function makeObject(_, argumentNames) { + var obj = {}; + var name; + var i; + var length = _.length; + var args = new Array(length); + + for (var x = 0; x < length; x++) { + args[x] = _[x]; + } + + for (i = 0; i < argumentNames.length; i++) { + name = argumentNames[i]; + obj[name] = args[i + 1]; + } + + return obj; + } + + function arrayResult(_) { + var length = _.length; + var args = new Array(length - 1); + + for (var i = 1; i < length; i++) { + args[i - 1] = _[i]; + } + + return args; + } + + function wrapThenable(then, promise) { + return { + then: function(onFulFillment, onRejection) { + return then.call(promise, onFulFillment, onRejection); + } + }; + } + + /** + `RSVP.denodeify` takes a 'node-style' function and returns a function that + will return an `RSVP.Promise`. You can use `denodeify` in Node.js or the + browser when you'd prefer to use promises over using callbacks. For example, + `denodeify` transforms the following: + + ```javascript + var fs = require('fs'); + + fs.readFile('myfile.txt', function(err, data){ + if (err) return handleError(err); + handleData(data); + }); + ``` + + into: + + ```javascript + var fs = require('fs'); + var readFile = RSVP.denodeify(fs.readFile); + + readFile('myfile.txt').then(handleData, handleError); + ``` + + If the node function has multiple success parameters, then `denodeify` + just returns the first one: + + ```javascript + var request = RSVP.denodeify(require('request')); + + request('http://example.com').then(function(res) { + // ... + }); + ``` + + However, if you need all success parameters, setting `denodeify`'s + second parameter to `true` causes it to return all success parameters + as an array: + + ```javascript + var request = RSVP.denodeify(require('request'), true); + + request('http://example.com').then(function(result) { + // result[0] -> res + // result[1] -> body + }); + ``` + + Or if you pass it an array with names it returns the parameters as a hash: + + ```javascript + var request = RSVP.denodeify(require('request'), ['res', 'body']); + + request('http://example.com').then(function(result) { + // result.res + // result.body + }); + ``` + + Sometimes you need to retain the `this`: + + ```javascript + var app = require('express')(); + var render = RSVP.denodeify(app.render.bind(app)); + ``` + + The denodified function inherits from the original function. It works in all + environments, except IE 10 and below. Consequently all properties of the original + function are available to you. However, any properties you change on the + denodeified function won't be changed on the original function. Example: + + ```javascript + var request = RSVP.denodeify(require('request')), + cookieJar = request.jar(); // <- Inheritance is used here + + request('http://example.com', {jar: cookieJar}).then(function(res) { + // cookieJar.cookies holds now the cookies returned by example.com + }); + ``` + + Using `denodeify` makes it easier to compose asynchronous operations instead + of using callbacks. For example, instead of: + + ```javascript + var fs = require('fs'); + + fs.readFile('myfile.txt', function(err, data){ + if (err) { ... } // Handle error + fs.writeFile('myfile2.txt', data, function(err){ + if (err) { ... } // Handle error + console.log('done') + }); + }); + ``` + + you can chain the operations together using `then` from the returned promise: + + ```javascript + var fs = require('fs'); + var readFile = RSVP.denodeify(fs.readFile); + var writeFile = RSVP.denodeify(fs.writeFile); + + readFile('myfile.txt').then(function(data){ + return writeFile('myfile2.txt', data); + }).then(function(){ + console.log('done') + }).catch(function(error){ + // Handle error + }); + ``` + + @method denodeify + @static + @for RSVP + @param {Function} nodeFunc a 'node-style' function that takes a callback as + its last argument. The callback expects an error to be passed as its first + argument (if an error occurred, otherwise null), and the value from the + operation as its second argument ('function(err, value){ }'). + @param {Boolean|Array} argumentNames An optional paramter that if set + to `true` causes the promise to fulfill with the callback's success arguments + as an array. This is useful if the node function has multiple success + paramters. If you set this paramter to an array with names, the promise will + fulfill with a hash with these names as keys and the success parameters as + values. + @return {Function} a function that wraps `nodeFunc` to return an + `RSVP.Promise` + @static + */ + __exports__["default"] = function denodeify(nodeFunc, options) { + var fn = function() { + var self = this; + var l = arguments.length; + var args = new Array(l + 1); + var arg; + var promiseInput = false; + + for (var i = 0; i < l; ++i) { + arg = arguments[i]; + + if (!promiseInput) { + // TODO: clean this up + promiseInput = needsPromiseInput(arg); + if (promiseInput === GET_THEN_ERROR) { + var p = new Promise(noop); + reject(p, GET_THEN_ERROR.value); + return p; + } else if (promiseInput && promiseInput !== true) { + arg = wrapThenable(promiseInput, arg); + } + } + args[i] = arg; + } + + var promise = new Promise(noop); + + args[l] = function(err, val) { + if (err) + reject(promise, err); + else if (options === undefined) + resolve(promise, val); + else if (options === true) + resolve(promise, arrayResult(arguments)); + else if (isArray(options)) + resolve(promise, makeObject(arguments, options)); + else + resolve(promise, val); + }; + + if (promiseInput) { + return handlePromiseInput(promise, args, nodeFunc, self); + } else { + return handleValueInput(promise, args, nodeFunc, self); + } + }; + + fn.__proto__ = nodeFunc; + + return fn; + } + + function handleValueInput(promise, args, nodeFunc, self) { + var result = tryApply(nodeFunc, self, args); + if (result === ERROR) { + reject(promise, result.value); + } + return promise; + } + + function handlePromiseInput(promise, args, nodeFunc, self){ + return Promise.all(args).then(function(args){ + var result = tryApply(nodeFunc, self, args); + if (result === ERROR) { + reject(promise, result.value); + } + return promise; + }); + } + + function needsPromiseInput(arg) { + if (arg && typeof arg === 'object') { + if (arg.constructor === Promise) { + return true; + } else { + return getThen(arg); + } + } else { + return false; + } + } + }); +define("rsvp/promise-hash", + ["./enumerator","./-internal","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Enumerator = __dependency1__["default"]; + var PENDING = __dependency2__.PENDING; + var o_create = __dependency3__.o_create; + + function PromiseHash(Constructor, object, label) { + this._superConstructor(Constructor, object, true, label); + } + + __exports__["default"] = PromiseHash; + + PromiseHash.prototype = o_create(Enumerator.prototype); + PromiseHash.prototype._superConstructor = Enumerator; + PromiseHash.prototype._init = function() { + this._result = {}; + }; + + PromiseHash.prototype._validateInput = function(input) { + return input && typeof input === 'object'; + }; + + PromiseHash.prototype._validationError = function() { + return new Error('Promise.hash must be called with an object'); + }; + + PromiseHash.prototype._enumerate = function() { + var promise = this.promise; + var input = this._input; + var results = []; + + for (var key in input) { + if (promise._state === PENDING && input.hasOwnProperty(key)) { + results.push({ + position: key, + entry: input[key] + }); + } + } + + var length = results.length; + this._remaining = length; + var result; + + for (var i = 0; promise._state === PENDING && i < length; i++) { + result = results[i]; + this._eachEntry(result.entry, result.position); + } + }; + }); +define("rsvp/promise", + ["./config","./instrument","./utils","./-internal","./promise/all","./promise/race","./promise/resolve","./promise/reject","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var config = __dependency1__.config; + var instrument = __dependency2__["default"]; + + var isFunction = __dependency3__.isFunction; + var now = __dependency3__.now; + + var noop = __dependency4__.noop; + var subscribe = __dependency4__.subscribe; + var initializePromise = __dependency4__.initializePromise; + var invokeCallback = __dependency4__.invokeCallback; + var FULFILLED = __dependency4__.FULFILLED; + var REJECTED = __dependency4__.REJECTED; + + var all = __dependency5__["default"]; + var race = __dependency6__["default"]; + var Resolve = __dependency7__["default"]; + var Reject = __dependency8__["default"]; + + var guidKey = 'rsvp_' + now() + '-'; + var counter = 0; + + function needsResolver() { + throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); + } + + function needsNew() { + throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); + } + __exports__["default"] = Promise; + /** + Promise objects represent the eventual result of an asynchronous operation. The + primary way of interacting with a promise is through its `then` method, which + registers callbacks to receive either a promise’s eventual value or the reason + why the promise cannot be fulfilled. + + Terminology + ----------- + + - `promise` is an object or function with a `then` method whose behavior conforms to this specification. + - `thenable` is an object or function that defines a `then` method. + - `value` is any legal JavaScript value (including undefined, a thenable, or a promise). + - `exception` is a value that is thrown using the throw statement. + - `reason` is a value that indicates why a promise was rejected. + - `settled` the final resting state of a promise, fulfilled or rejected. + + A promise can be in one of three states: pending, fulfilled, or rejected. + + Promises that are fulfilled have a fulfillment value and are in the fulfilled + state. Promises that are rejected have a rejection reason and are in the + rejected state. A fulfillment value is never a thenable. + + Promises can also be said to *resolve* a value. If this value is also a + promise, then the original promise's settled state will match the value's + settled state. So a promise that *resolves* a promise that rejects will + itself reject, and a promise that *resolves* a promise that fulfills will + itself fulfill. + + + Basic Usage: + ------------ + + ```js + var promise = new Promise(function(resolve, reject) { + // on success + resolve(value); + + // on failure + reject(reason); + }); + + promise.then(function(value) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Advanced Usage: + --------------- + + Promises shine when abstracting away asynchronous interactions such as + `XMLHttpRequest`s. + + ```js + function getJSON(url) { + return new Promise(function(resolve, reject){ + var xhr = new XMLHttpRequest(); + + xhr.open('GET', url); + xhr.onreadystatechange = handler; + xhr.responseType = 'json'; + xhr.setRequestHeader('Accept', 'application/json'); + xhr.send(); + + function handler() { + if (this.readyState === this.DONE) { + if (this.status === 200) { + resolve(this.response); + } else { + reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']')); + } + } + }; + }); + } + + getJSON('/posts.json').then(function(json) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Unlike callbacks, promises are great composable primitives. + + ```js + Promise.all([ + getJSON('/posts'), + getJSON('/comments') + ]).then(function(values){ + values[0] // => postsJSON + values[1] // => commentsJSON + + return values; + }); + ``` + + @class RSVP.Promise + @param {function} resolver + @param {String} label optional string for labeling the promise. + Useful for tooling. + @constructor + */ + function Promise(resolver, label) { + this._id = counter++; + this._label = label; + this._state = undefined; + this._result = undefined; + this._subscribers = []; + + if (config.instrument) { + instrument('created', this); + } + + if (noop !== resolver) { + if (!isFunction(resolver)) { + needsResolver(); + } + + if (!(this instanceof Promise)) { + needsNew(); + } + + initializePromise(this, resolver); + } + } + + Promise.cast = Resolve; // deprecated + Promise.all = all; + Promise.race = race; + Promise.resolve = Resolve; + Promise.reject = Reject; + + Promise.prototype = { + constructor: Promise, + + _guidKey: guidKey, + + _onerror: function (reason) { + config.trigger('error', reason); + }, + + /** + The primary way of interacting with a promise is through its `then` method, + which registers callbacks to receive either a promise's eventual value or the + reason why the promise cannot be fulfilled. + + ```js + findUser().then(function(user){ + // user is available + }, function(reason){ + // user is unavailable, and you are given the reason why + }); + ``` + + Chaining + -------- + + The return value of `then` is itself a promise. This second, 'downstream' + promise is resolved with the return value of the first promise's fulfillment + or rejection handler, or rejected if the handler throws an exception. + + ```js + findUser().then(function (user) { + return user.name; + }, function (reason) { + return 'default name'; + }).then(function (userName) { + // If `findUser` fulfilled, `userName` will be the user's name, otherwise it + // will be `'default name'` + }); + + findUser().then(function (user) { + throw new Error('Found user, but still unhappy'); + }, function (reason) { + throw new Error('`findUser` rejected and we're unhappy'); + }).then(function (value) { + // never reached + }, function (reason) { + // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'. + // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'. + }); + ``` + If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. + + ```js + findUser().then(function (user) { + throw new PedagogicalException('Upstream error'); + }).then(function (value) { + // never reached + }).then(function (value) { + // never reached + }, function (reason) { + // The `PedgagocialException` is propagated all the way down to here + }); + ``` + + Assimilation + ------------ + + Sometimes the value you want to propagate to a downstream promise can only be + retrieved asynchronously. This can be achieved by returning a promise in the + fulfillment or rejection handler. The downstream promise will then be pending + until the returned promise is settled. This is called *assimilation*. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // The user's comments are now available + }); + ``` + + If the assimliated promise rejects, then the downstream promise will also reject. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // If `findCommentsByAuthor` fulfills, we'll have the value here + }, function (reason) { + // If `findCommentsByAuthor` rejects, we'll have the reason here + }); + ``` + + Simple Example + -------------- + + Synchronous Example + + ```javascript + var result; + + try { + result = findResult(); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + findResult(function(result, err){ + if (err) { + // failure + } else { + // success + } + }); + ``` + + Promise Example; + + ```javascript + findResult().then(function(result){ + // success + }, function(reason){ + // failure + }); + ``` + + Advanced Example + -------------- + + Synchronous Example + + ```javascript + var author, books; + + try { + author = findAuthor(); + books = findBooksByAuthor(author); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + + function foundBooks(books) { + + } + + function failure(reason) { + + } + + findAuthor(function(author, err){ + if (err) { + failure(err); + // failure + } else { + try { + findBoooksByAuthor(author, function(books, err) { + if (err) { + failure(err); + } else { + try { + foundBooks(books); + } catch(reason) { + failure(reason); + } + } + }); + } catch(error) { + failure(err); + } + // success + } + }); + ``` + + Promise Example; + + ```javascript + findAuthor(). + then(findBooksByAuthor). + then(function(books){ + // found books + }).catch(function(reason){ + // something went wrong + }); + ``` + + @method then + @param {Function} onFulfilled + @param {Function} onRejected + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + then: function(onFulfillment, onRejection, label) { + var parent = this; + var state = parent._state; + + if (state === FULFILLED && !onFulfillment || state === REJECTED && !onRejection) { + if (config.instrument) { + instrument('chained', this, this); + } + return this; + } + + parent._onerror = null; + + var child = new this.constructor(noop, label); + var result = parent._result; + + if (config.instrument) { + instrument('chained', parent, child); + } + + if (state) { + var callback = arguments[state - 1]; + config.async(function(){ + invokeCallback(state, child, callback, result); + }); + } else { + subscribe(parent, child, onFulfillment, onRejection); + } + + return child; + }, + + /** + `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same + as the catch block of a try/catch statement. + + ```js + function findAuthor(){ + throw new Error('couldn't find that author'); + } + + // synchronous + try { + findAuthor(); + } catch(reason) { + // something went wrong + } + + // async with promises + findAuthor().catch(function(reason){ + // something went wrong + }); + ``` + + @method catch + @param {Function} onRejection + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + 'catch': function(onRejection, label) { + return this.then(null, onRejection, label); + }, + + /** + `finally` will be invoked regardless of the promise's fate just as native + try/catch/finally behaves + + Synchronous example: + + ```js + findAuthor() { + if (Math.random() > 0.5) { + throw new Error(); + } + return new Author(); + } + + try { + return findAuthor(); // succeed or fail + } catch(error) { + return findOtherAuther(); + } finally { + // always runs + // doesn't affect the return value + } + ``` + + Asynchronous example: + + ```js + findAuthor().catch(function(reason){ + return findOtherAuther(); + }).finally(function(){ + // author was either found, or not + }); + ``` + + @method finally + @param {Function} callback + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + 'finally': function(callback, label) { + var constructor = this.constructor; + + return this.then(function(value) { + return constructor.resolve(callback()).then(function(){ + return value; + }); + }, function(reason) { + return constructor.resolve(callback()).then(function(){ + throw reason; + }); + }, label); + } + }; + }); +define("rsvp/promise/all", + ["../enumerator","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Enumerator = __dependency1__["default"]; + + /** + `RSVP.Promise.all` accepts an array of promises, and returns a new promise which + is fulfilled with an array of fulfillment values for the passed promises, or + rejected with the reason of the first passed promise to be rejected. It casts all + elements of the passed iterable to promises as it runs this algorithm. + + Example: + + ```javascript + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.resolve(2); + var promise3 = RSVP.resolve(3); + var promises = [ promise1, promise2, promise3 ]; + + RSVP.Promise.all(promises).then(function(array){ + // The array here would be [ 1, 2, 3 ]; + }); + ``` + + If any of the `promises` given to `RSVP.all` are rejected, the first promise + that is rejected will be given as an argument to the returned promises's + rejection handler. For example: + + Example: + + ```javascript + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.reject(new Error("2")); + var promise3 = RSVP.reject(new Error("3")); + var promises = [ promise1, promise2, promise3 ]; + + RSVP.Promise.all(promises).then(function(array){ + // Code here never runs because there are rejected promises! + }, function(error) { + // error.message === "2" + }); + ``` + + @method all + @static + @param {Array} entries array of promises + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled when all `promises` have been + fulfilled, or rejected if any of them become rejected. + @static + */ + __exports__["default"] = function all(entries, label) { + return new Enumerator(this, entries, true /* abort on reject */, label).promise; + } + }); +define("rsvp/promise/race", + ["../utils","../-internal","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var isArray = __dependency1__.isArray; + + var noop = __dependency2__.noop; + var resolve = __dependency2__.resolve; + var reject = __dependency2__.reject; + var subscribe = __dependency2__.subscribe; + var PENDING = __dependency2__.PENDING; + + /** + `RSVP.Promise.race` returns a new promise which is settled in the same way as the + first passed promise to settle. + + Example: + + ```javascript + var promise1 = new RSVP.Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 1'); + }, 200); + }); + + var promise2 = new RSVP.Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 2'); + }, 100); + }); + + RSVP.Promise.race([promise1, promise2]).then(function(result){ + // result === 'promise 2' because it was resolved before promise1 + // was resolved. + }); + ``` + + `RSVP.Promise.race` is deterministic in that only the state of the first + settled promise matters. For example, even if other promises given to the + `promises` array argument are resolved, but the first settled promise has + become rejected before the other promises became fulfilled, the returned + promise will become rejected: + + ```javascript + var promise1 = new RSVP.Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 1'); + }, 200); + }); + + var promise2 = new RSVP.Promise(function(resolve, reject){ + setTimeout(function(){ + reject(new Error('promise 2')); + }, 100); + }); + + RSVP.Promise.race([promise1, promise2]).then(function(result){ + // Code here never runs + }, function(reason){ + // reason.message === 'promise 2' because promise 2 became rejected before + // promise 1 became fulfilled + }); + ``` + + An example real-world use case is implementing timeouts: + + ```javascript + RSVP.Promise.race([ajax('foo.json'), timeout(5000)]) + ``` + + @method race + @static + @param {Array} promises array of promises to observe + @param {String} label optional string for describing the promise returned. + Useful for tooling. + @return {Promise} a promise which settles in the same way as the first passed + promise to settle. + */ + __exports__["default"] = function race(entries, label) { + /*jshint validthis:true */ + var Constructor = this; + + var promise = new Constructor(noop, label); + + if (!isArray(entries)) { + reject(promise, new TypeError('You must pass an array to race.')); + return promise; + } + + var length = entries.length; + + function onFulfillment(value) { + resolve(promise, value); + } + + function onRejection(reason) { + reject(promise, reason); + } + + for (var i = 0; promise._state === PENDING && i < length; i++) { + subscribe(Constructor.resolve(entries[i]), undefined, onFulfillment, onRejection); + } + + return promise; + } + }); +define("rsvp/promise/reject", + ["../-internal","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var noop = __dependency1__.noop; + var _reject = __dependency1__.reject; + + /** + `RSVP.Promise.reject` returns a promise rejected with the passed `reason`. + It is shorthand for the following: + + ```javascript + var promise = new RSVP.Promise(function(resolve, reject){ + reject(new Error('WHOOPS')); + }); + + promise.then(function(value){ + // Code here doesn't run because the promise is rejected! + }, function(reason){ + // reason.message === 'WHOOPS' + }); + ``` + + Instead of writing the above, your code now simply becomes the following: + + ```javascript + var promise = RSVP.Promise.reject(new Error('WHOOPS')); + + promise.then(function(value){ + // Code here doesn't run because the promise is rejected! + }, function(reason){ + // reason.message === 'WHOOPS' + }); + ``` + + @method reject + @static + @param {Any} reason value that the returned promise will be rejected with. + @param {String} label optional string for identifying the returned promise. + Useful for tooling. + @return {Promise} a promise rejected with the given `reason`. + */ + __exports__["default"] = function reject(reason, label) { + /*jshint validthis:true */ + var Constructor = this; + var promise = new Constructor(noop, label); + _reject(promise, reason); + return promise; + } + }); +define("rsvp/promise/resolve", + ["../-internal","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var noop = __dependency1__.noop; + var _resolve = __dependency1__.resolve; + + /** + `RSVP.Promise.resolve` returns a promise that will become resolved with the + passed `value`. It is shorthand for the following: + + ```javascript + var promise = new RSVP.Promise(function(resolve, reject){ + resolve(1); + }); + + promise.then(function(value){ + // value === 1 + }); + ``` + + Instead of writing the above, your code now simply becomes the following: + + ```javascript + var promise = RSVP.Promise.resolve(1); + + promise.then(function(value){ + // value === 1 + }); + ``` + + @method resolve + @static + @param {Any} value value that the returned promise will be resolved with + @param {String} label optional string for identifying the returned promise. + Useful for tooling. + @return {Promise} a promise that will become fulfilled with the given + `value` + */ + __exports__["default"] = function resolve(object, label) { + /*jshint validthis:true */ + var Constructor = this; + + if (object && typeof object === 'object' && object.constructor === Constructor) { + return object; + } + + var promise = new Constructor(noop, label); + _resolve(promise, object); + return promise; + } + }); +define("rsvp/race", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + This is a convenient alias for `RSVP.Promise.race`. + + @method race + @static + @for RSVP + @param {Array} array Array of promises. + @param {String} label An optional label. This is useful + for tooling. + */ + __exports__["default"] = function race(array, label) { + return Promise.race(array, label); + } + }); +define("rsvp/reject", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + This is a convenient alias for `RSVP.Promise.reject`. + + @method reject + @static + @for RSVP + @param {Any} reason value that the returned promise will be rejected with. + @param {String} label optional string for identifying the returned promise. + Useful for tooling. + @return {Promise} a promise rejected with the given `reason`. + */ + __exports__["default"] = function reject(reason, label) { + return Promise.reject(reason, label); + } + }); +define("rsvp/resolve", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + This is a convenient alias for `RSVP.Promise.resolve`. + + @method resolve + @static + @for RSVP + @param {Any} value value that the returned promise will be resolved with + @param {String} label optional string for identifying the returned promise. + Useful for tooling. + @return {Promise} a promise that will become fulfilled with the given + `value` + */ + __exports__["default"] = function resolve(value, label) { + return Promise.resolve(value, label); + } + }); +define("rsvp/rethrow", + ["exports"], + function(__exports__) { + "use strict"; + /** + `RSVP.rethrow` will rethrow an error on the next turn of the JavaScript event + loop in order to aid debugging. + + Promises A+ specifies that any exceptions that occur with a promise must be + caught by the promises implementation and bubbled to the last handler. For + this reason, it is recommended that you always specify a second rejection + handler function to `then`. However, `RSVP.rethrow` will throw the exception + outside of the promise, so it bubbles up to your console if in the browser, + or domain/cause uncaught exception in Node. `rethrow` will also throw the + error again so the error can be handled by the promise per the spec. + + ```javascript + function throws(){ + throw new Error('Whoops!'); + } + + var promise = new RSVP.Promise(function(resolve, reject){ + throws(); + }); + + promise.catch(RSVP.rethrow).then(function(){ + // Code here doesn't run because the promise became rejected due to an + // error! + }, function (err){ + // handle the error here + }); + ``` + + The 'Whoops' error will be thrown on the next turn of the event loop + and you can watch for it in your console. You can also handle it using a + rejection handler given to `.then` or `.catch` on the returned promise. + + @method rethrow + @static + @for RSVP + @param {Error} reason reason the promise became rejected. + @throws Error + @static + */ + __exports__["default"] = function rethrow(reason) { + setTimeout(function() { + throw reason; + }); + throw reason; + } + }); +define("rsvp/utils", + ["exports"], + function(__exports__) { + "use strict"; + function objectOrFunction(x) { + return typeof x === 'function' || (typeof x === 'object' && x !== null); + } + + __exports__.objectOrFunction = objectOrFunction;function isFunction(x) { + return typeof x === 'function'; + } + + __exports__.isFunction = isFunction;function isMaybeThenable(x) { + return typeof x === 'object' && x !== null; + } + + __exports__.isMaybeThenable = isMaybeThenable;var _isArray; + if (!Array.isArray) { + _isArray = function (x) { + return Object.prototype.toString.call(x) === '[object Array]'; + }; + } else { + _isArray = Array.isArray; + } + + var isArray = _isArray; + __exports__.isArray = isArray; + // Date.now is not available in browsers < IE9 + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility + var now = Date.now || function() { return new Date().getTime(); }; + __exports__.now = now; + function F() { } + + var o_create = (Object.create || function (o) { + if (arguments.length > 1) { + throw new Error('Second argument not supported'); + } + if (typeof o !== 'object') { + throw new TypeError('Argument must be an object'); + } + F.prototype = o; + return new F(); + }); + __exports__.o_create = o_create; + }); +requireModule("ember"); + +})(); \ No newline at end of file diff --git a/assets/stylesheets/style.css.scss b/assets/stylesheets/style.css.scss new file mode 100644 index 0000000..58f262b --- /dev/null +++ b/assets/stylesheets/style.css.scss @@ -0,0 +1,154 @@ +//= require bootstrap/dist/css/bootstrap.min +//= require bootstrap/dist/css/bootstrap-theme.min + +/*@import url(http://fonts.googleapis.com/css?family=Abel);*/ + +$red: #fc3932; +$darkred: #cc2b1f; +$grey: #ccc; +$darkgrey: #aaa; + +$cellWidth: 30px; +$cellHeight: 30px; + +body { + font-family: Abel, sans-serif; +} + +.button, .toggle-button { + outline: none; + border: none; + color: #fff; + display: inline-block; + padding: 0; + vertical-align: top; +} + +.knob { + display: inline-block; + padding: 10px; + /*background: blue;*/ + + p { + text-align: center; + margin-top: -5px; + } +} + +.waveform { + width: 120px; + display: inline-block; + vertical-align: top; + text-align: center; +} + +.toggle-button { + background-color: $grey; + width: $cellWidth; + height: $cellHeight; + margin-bottom: 2px; + + &.on { + background-color: $red; + } +} + +.waveform-button { + padding: 10px; +} + +.pitch-label { + background-color: #e6e6e6; + height: $cellHeight; + margin-bottom: 2px; + line-height: $cellHeight; + font-size: 1.5em; + text-align: center; +} + +.step-label { + background-color: #f2f2f2; + margin-bottom: 2px; + line-height: $cellHeight; + text-align: center; + font-size: 1.5em; +} + +.column { + padding-left: 12px; + padding-top: 10px; + display: inline-block; + width: 270px; + + .button { + width: 126px; + height: 62px; + padding: 10px 20px; + margin-bottom: 2px; + } + + .button + .button { + margin-left: 2px; + } + + .pattern-button { + width: $cellWidth; + height: $cellHeight; + padding: 0; + } + + .pattern-button + .pattern-button { + margin-left: 2px; + } +} + +.step-column { + width: $cellWidth; + box-sizing: content-box; + padding-left: 2px; + display: inline-block; + line-height: 0; + padding-top: 5px; + border-top: 5px solid transparent; + + &.highlight { + .step-label { + background-color: #e6e6e6; + } + + .button.grey { + background-color: #aaaaaa; + } + } +} + +.playing { + border-top: 5px solid $red; +} + +.grid { + display: inline-flex; + align-items: flex-start; +} + +.pitch-button { + width: $cellWidth; + height: $cellHeight; + margin-bottom: 2px; +} + +.button { + background-color: $red; + + &:active { + background-color: $darkred; + } +} + +.button.grey { + background-color: $grey; + + &:active { + background-color: $darkgrey; + } +} diff --git a/bower_components/bootstrap/.bower.json b/bower_components/bootstrap/.bower.json new file mode 100644 index 0000000..1fc4d13 --- /dev/null +++ b/bower_components/bootstrap/.bower.json @@ -0,0 +1,48 @@ +{ + "name": "bootstrap", + "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.", + "version": "3.3.0", + "keywords": [ + "css", + "js", + "less", + "mobile-first", + "responsive", + "front-end", + "framework", + "web" + ], + "homepage": "http://getbootstrap.com", + "main": [ + "less/bootstrap.less", + "dist/css/bootstrap.css", + "dist/js/bootstrap.js", + "dist/fonts/glyphicons-halflings-regular.eot", + "dist/fonts/glyphicons-halflings-regular.svg", + "dist/fonts/glyphicons-halflings-regular.ttf", + "dist/fonts/glyphicons-halflings-regular.woff" + ], + "ignore": [ + "/.*", + "_config.yml", + "CNAME", + "composer.json", + "CONTRIBUTING.md", + "docs", + "js/tests", + "test-infra" + ], + "dependencies": { + "jquery": ">= 1.9.1" + }, + "_release": "3.3.0", + "_resolution": { + "type": "version", + "tag": "v3.3.0", + "commit": "16dbdbd7a2c6cfa3be4e5dcc52249e577c02c84a" + }, + "_source": "git://github.com/twbs/bootstrap.git", + "_target": "~3.3.0", + "_originalSource": "bootstrap", + "_direct": true +} \ No newline at end of file diff --git a/bower_components/bootstrap/Gruntfile.js b/bower_components/bootstrap/Gruntfile.js new file mode 100644 index 0000000..cbf01ac --- /dev/null +++ b/bower_components/bootstrap/Gruntfile.js @@ -0,0 +1,502 @@ +/*! + * Bootstrap's Gruntfile + * http://getbootstrap.com + * Copyright 2013-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +module.exports = function (grunt) { + 'use strict'; + + // Force use of Unix newlines + grunt.util.linefeed = '\n'; + + RegExp.quote = function (string) { + return string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&'); + }; + + var fs = require('fs'); + var path = require('path'); + var npmShrinkwrap = require('npm-shrinkwrap'); + var BsLessdocParser = require('./grunt/bs-lessdoc-parser.js'); + var getLessVarsData = function () { + var filePath = path.join(__dirname, 'less/variables.less'); + var fileContent = fs.readFileSync(filePath, { encoding: 'utf8' }); + var parser = new BsLessdocParser(fileContent); + return { sections: parser.parseFile() }; + }; + var generateRawFiles = require('./grunt/bs-raw-files-generator.js'); + var generateCommonJSModule = require('./grunt/bs-commonjs-generator.js'); + + // Project configuration. + grunt.initConfig({ + + // Metadata. + pkg: grunt.file.readJSON('package.json'), + banner: '/*!\n' + + ' * Bootstrap v<%= pkg.version %> (<%= pkg.homepage %>)\n' + + ' * Copyright 2011-<%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' + + ' * Licensed under <%= pkg.license.type %> (<%= pkg.license.url %>)\n' + + ' */\n', + // NOTE: This jqueryCheck/jqueryVersionCheck code is duplicated in customizer.js; + // if making changes here, be sure to update the other copy too. + jqueryCheck: [ + 'if (typeof jQuery === \'undefined\') {', + ' throw new Error(\'Bootstrap\\\'s JavaScript requires jQuery\')', + '}\n' + ].join('\n'), + jqueryVersionCheck: [ + '+function ($) {', + ' var version = $.fn.jquery.split(\' \')[0].split(\'.\')', + ' if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) {', + ' throw new Error(\'Bootstrap\\\'s JavaScript requires jQuery version 1.9.1 or higher\')', + ' }', + '}(jQuery);\n\n' + ].join('\n'), + + // Task configuration. + clean: { + dist: 'dist', + docs: 'docs/dist' + }, + + jshint: { + options: { + jshintrc: 'js/.jshintrc' + }, + grunt: { + options: { + jshintrc: 'grunt/.jshintrc' + }, + src: ['Gruntfile.js', 'grunt/*.js'] + }, + core: { + src: 'js/*.js' + }, + test: { + options: { + jshintrc: 'js/tests/unit/.jshintrc' + }, + src: 'js/tests/unit/*.js' + }, + assets: { + src: ['docs/assets/js/src/*.js', 'docs/assets/js/*.js', '!docs/assets/js/*.min.js'] + } + }, + + jscs: { + options: { + config: 'js/.jscsrc' + }, + grunt: { + src: '<%= jshint.grunt.src %>' + }, + core: { + src: '<%= jshint.core.src %>' + }, + test: { + src: '<%= jshint.test.src %>' + }, + assets: { + options: { + requireCamelCaseOrUpperCaseIdentifiers: null + }, + src: '<%= jshint.assets.src %>' + } + }, + + concat: { + options: { + banner: '<%= banner %>\n<%= jqueryCheck %>\n<%= jqueryVersionCheck %>', + stripBanners: false + }, + bootstrap: { + src: [ + 'js/transition.js', + 'js/alert.js', + 'js/button.js', + 'js/carousel.js', + 'js/collapse.js', + 'js/dropdown.js', + 'js/modal.js', + 'js/tooltip.js', + 'js/popover.js', + 'js/scrollspy.js', + 'js/tab.js', + 'js/affix.js' + ], + dest: 'dist/js/<%= pkg.name %>.js' + } + }, + + uglify: { + options: { + preserveComments: 'some' + }, + core: { + src: '<%= concat.bootstrap.dest %>', + dest: 'dist/js/<%= pkg.name %>.min.js' + }, + customize: { + // NOTE: This src list is duplicated in footer.html; if making changes here, be sure to update the other copy too. + src: [ + 'docs/assets/js/vendor/less.min.js', + 'docs/assets/js/vendor/jszip.min.js', + 'docs/assets/js/vendor/uglify.min.js', + 'docs/assets/js/vendor/Blob.js', + 'docs/assets/js/vendor/FileSaver.js', + 'docs/assets/js/raw-files.min.js', + 'docs/assets/js/src/customizer.js' + ], + dest: 'docs/assets/js/customize.min.js' + }, + docsJs: { + // NOTE: This src list is duplicated in footer.html; if making changes here, be sure to update the other copy too. + src: [ + 'docs/assets/js/vendor/holder.js', + 'docs/assets/js/vendor/ZeroClipboard.min.js', + 'docs/assets/js/src/application.js' + ], + dest: 'docs/assets/js/docs.min.js' + } + }, + + qunit: { + options: { + inject: 'js/tests/unit/phantom.js' + }, + files: 'js/tests/index.html' + }, + + less: { + compileCore: { + options: { + strictMath: true, + sourceMap: true, + outputSourceFiles: true, + sourceMapURL: '<%= pkg.name %>.css.map', + sourceMapFilename: 'dist/css/<%= pkg.name %>.css.map' + }, + src: 'less/bootstrap.less', + dest: 'dist/css/<%= pkg.name %>.css' + }, + compileTheme: { + options: { + strictMath: true, + sourceMap: true, + outputSourceFiles: true, + sourceMapURL: '<%= pkg.name %>-theme.css.map', + sourceMapFilename: 'dist/css/<%= pkg.name %>-theme.css.map' + }, + src: 'less/theme.less', + dest: 'dist/css/<%= pkg.name %>-theme.css' + } + }, + + autoprefixer: { + options: { + browsers: [ + 'Android 2.3', + 'Android >= 4', + 'Chrome >= 20', + 'Firefox >= 24', // Firefox 24 is the latest ESR + 'Explorer >= 8', + 'iOS >= 6', + 'Opera >= 12', + 'Safari >= 6' + ] + }, + core: { + options: { + map: true + }, + src: 'dist/css/<%= pkg.name %>.css' + }, + theme: { + options: { + map: true + }, + src: 'dist/css/<%= pkg.name %>-theme.css' + }, + docs: { + src: 'docs/assets/css/src/docs.css' + }, + examples: { + expand: true, + cwd: 'docs/examples/', + src: ['**/*.css'], + dest: 'docs/examples/' + } + }, + + csslint: { + options: { + csslintrc: 'less/.csslintrc' + }, + dist: [ + 'dist/css/bootstrap.css', + 'dist/css/bootstrap-theme.css' + ], + examples: [ + 'docs/examples/**/*.css' + ], + docs: { + options: { + ids: false, + 'overqualified-elements': false + }, + src: 'docs/assets/css/src/docs.css' + } + }, + + cssmin: { + options: { + compatibility: 'ie8', + keepSpecialComments: '*', + noAdvanced: true + }, + minifyCore: { + src: 'dist/css/<%= pkg.name %>.css', + dest: 'dist/css/<%= pkg.name %>.min.css' + }, + minifyTheme: { + src: 'dist/css/<%= pkg.name %>-theme.css', + dest: 'dist/css/<%= pkg.name %>-theme.min.css' + }, + docs: { + src: [ + 'docs/assets/css/src/docs.css', + 'docs/assets/css/src/pygments-manni.css' + ], + dest: 'docs/assets/css/docs.min.css' + } + }, + + usebanner: { + options: { + position: 'top', + banner: '<%= banner %>' + }, + files: { + src: 'dist/css/*.css' + } + }, + + csscomb: { + options: { + config: 'less/.csscomb.json' + }, + dist: { + expand: true, + cwd: 'dist/css/', + src: ['*.css', '!*.min.css'], + dest: 'dist/css/' + }, + examples: { + expand: true, + cwd: 'docs/examples/', + src: '**/*.css', + dest: 'docs/examples/' + }, + docs: { + src: 'docs/assets/css/src/docs.css', + dest: 'docs/assets/css/src/docs.css' + } + }, + + copy: { + fonts: { + src: 'fonts/*', + dest: 'dist/' + }, + docs: { + src: 'dist/*/*', + dest: 'docs/' + } + }, + + connect: { + server: { + options: { + port: 3000, + base: '.' + } + } + }, + + jekyll: { + docs: {} + }, + + jade: { + options: { + pretty: true, + data: getLessVarsData + }, + customizerVars: { + src: 'docs/_jade/customizer-variables.jade', + dest: 'docs/_includes/customizer-variables.html' + }, + customizerNav: { + src: 'docs/_jade/customizer-nav.jade', + dest: 'docs/_includes/nav/customize.html' + } + }, + + validation: { + options: { + charset: 'utf-8', + doctype: 'HTML5', + failHard: true, + reset: true, + relaxerror: [ + 'Bad value X-UA-Compatible for attribute http-equiv on element meta.', + 'Element img is missing required attribute src.', + 'Attribute autocomplete not allowed on element input at this point.', + 'Attribute autocomplete not allowed on element button at this point.' + ] + }, + files: { + src: '_gh_pages/**/*.html' + } + }, + + watch: { + src: { + files: '<%= jshint.core.src %>', + tasks: ['jshint:src', 'qunit', 'concat'] + }, + test: { + files: '<%= jshint.test.src %>', + tasks: ['jshint:test', 'qunit'] + }, + less: { + files: 'less/**/*.less', + tasks: 'less' + } + }, + + sed: { + versionNumber: { + pattern: (function () { + var old = grunt.option('oldver'); + return old ? RegExp.quote(old) : old; + })(), + replacement: grunt.option('newver'), + recursive: true + } + }, + + 'saucelabs-qunit': { + all: { + options: { + build: process.env.TRAVIS_JOB_ID, + concurrency: 10, + maxRetries: 3, + urls: ['http://127.0.0.1:3000/js/tests/index.html'], + browsers: grunt.file.readYAML('grunt/sauce_browsers.yml') + } + } + }, + + exec: { + npmUpdate: { + command: 'npm update' + } + } + }); + + + // These plugins provide necessary tasks. + require('load-grunt-tasks')(grunt, { scope: 'devDependencies' }); + require('time-grunt')(grunt); + + // Docs HTML validation task + grunt.registerTask('validate-html', ['jekyll', 'validation']); + + var runSubset = function (subset) { + return !process.env.TWBS_TEST || process.env.TWBS_TEST === subset; + }; + var isUndefOrNonZero = function (val) { + return val === undefined || val !== '0'; + }; + + // Test task. + var testSubtasks = []; + // Skip core tests if running a different subset of the test suite + if (runSubset('core')) { + testSubtasks = testSubtasks.concat(['dist-css', 'dist-js', 'csslint:dist', 'test-js', 'docs']); + } + // Skip HTML validation if running a different subset of the test suite + if (runSubset('validate-html') && + // Skip HTML5 validator on Travis when [skip validator] is in the commit message + isUndefOrNonZero(process.env.TWBS_DO_VALIDATOR)) { + testSubtasks.push('validate-html'); + } + // Only run Sauce Labs tests if there's a Sauce access key + if (typeof process.env.SAUCE_ACCESS_KEY !== 'undefined' && + // Skip Sauce if running a different subset of the test suite + runSubset('sauce-js-unit') && + // Skip Sauce on Travis when [skip sauce] is in the commit message + isUndefOrNonZero(process.env.TWBS_DO_SAUCE)) { + testSubtasks.push('connect'); + testSubtasks.push('saucelabs-qunit'); + } + grunt.registerTask('test', testSubtasks); + grunt.registerTask('test-js', ['jshint:core', 'jshint:test', 'jshint:grunt', 'jscs:core', 'jscs:test', 'jscs:grunt', 'qunit']); + + // JS distribution task. + grunt.registerTask('dist-js', ['concat', 'uglify:core', 'commonjs']); + + // CSS distribution task. + grunt.registerTask('less-compile', ['less:compileCore', 'less:compileTheme']); + grunt.registerTask('dist-css', ['less-compile', 'autoprefixer:core', 'autoprefixer:theme', 'usebanner', 'csscomb:dist', 'cssmin:minifyCore', 'cssmin:minifyTheme']); + + // Full distribution task. + grunt.registerTask('dist', ['clean:dist', 'dist-css', 'copy:fonts', 'dist-js']); + + // Default task. + grunt.registerTask('default', ['clean:dist', 'copy:fonts', 'test']); + + // Version numbering task. + // grunt change-version-number --oldver=A.B.C --newver=X.Y.Z + // This can be overzealous, so its changes should always be manually reviewed! + grunt.registerTask('change-version-number', 'sed'); + + // task for building customizer + grunt.registerTask('build-customizer', ['build-customizer-html', 'build-raw-files']); + grunt.registerTask('build-customizer-html', 'jade'); + grunt.registerTask('build-raw-files', 'Add scripts/less files to customizer.', function () { + var banner = grunt.template.process('<%= banner %>'); + generateRawFiles(grunt, banner); + }); + + grunt.registerTask('commonjs', 'Generate CommonJS entrypoint module in dist dir.', function () { + var srcFiles = grunt.config.get('concat.bootstrap.src'); + var destFilepath = 'dist/js/npm.js'; + generateCommonJSModule(grunt, srcFiles, destFilepath); + }); + + // Docs task. + grunt.registerTask('docs-css', ['autoprefixer:docs', 'autoprefixer:examples', 'csscomb:docs', 'csscomb:examples', 'cssmin:docs']); + grunt.registerTask('lint-docs-css', ['csslint:docs', 'csslint:examples']); + grunt.registerTask('docs-js', ['uglify:docsJs', 'uglify:customize']); + grunt.registerTask('lint-docs-js', ['jshint:assets', 'jscs:assets']); + grunt.registerTask('docs', ['docs-css', 'lint-docs-css', 'docs-js', 'lint-docs-js', 'clean:docs', 'copy:docs', 'build-customizer']); + + // Task for updating the cached npm packages used by the Travis build (which are controlled by test-infra/npm-shrinkwrap.json). + // This task should be run and the updated file should be committed whenever Bootstrap's dependencies change. + grunt.registerTask('update-shrinkwrap', ['exec:npmUpdate', '_update-shrinkwrap']); + grunt.registerTask('_update-shrinkwrap', function () { + var done = this.async(); + npmShrinkwrap({ dev: true, dirname: __dirname }, function (err) { + if (err) { + grunt.fail.warn(err); + } + var dest = 'test-infra/npm-shrinkwrap.json'; + fs.renameSync('npm-shrinkwrap.json', dest); + grunt.log.writeln('File ' + dest.cyan + ' updated.'); + done(); + }); + }); +}; diff --git a/bower_components/bootstrap/LICENSE b/bower_components/bootstrap/LICENSE new file mode 100644 index 0000000..8d94aa9 --- /dev/null +++ b/bower_components/bootstrap/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2011-2014 Twitter, Inc + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/bower_components/bootstrap/README.md b/bower_components/bootstrap/README.md new file mode 100644 index 0000000..52bf7c3 --- /dev/null +++ b/bower_components/bootstrap/README.md @@ -0,0 +1,129 @@ +# [Bootstrap](http://getbootstrap.com) +[![Bower version](https://badge.fury.io/bo/bootstrap.svg)](http://badge.fury.io/bo/bootstrap) +[![NPM version](https://badge.fury.io/js/bootstrap.svg)](http://badge.fury.io/js/bootstrap) +[![Build Status](https://secure.travis-ci.org/twbs/bootstrap.svg?branch=master)](https://travis-ci.org/twbs/bootstrap) +[![devDependency Status](https://david-dm.org/twbs/bootstrap/dev-status.svg)](https://david-dm.org/twbs/bootstrap#info=devDependencies) +[![Selenium Test Status](https://saucelabs.com/browser-matrix/bootstrap.svg)](https://saucelabs.com/u/bootstrap) + +Bootstrap is a sleek, intuitive, and powerful front-end framework for faster and easier web development, created by [Mark Otto](https://twitter.com/mdo) and [Jacob Thornton](https://twitter.com/fat), and maintained by the [core team](https://github.com/twbs?tab=members) with the massive support and involvement of the community. + +To get started, check out ! + +## Table of contents + +- [Quick start](#quick-start) +- [Bugs and feature requests](#bugs-and-feature-requests) +- [Documentation](#documentation) +- [Contributing](#contributing) +- [Community](#community) +- [Versioning](#versioning) +- [Creators](#creators) +- [Copyright and license](#copyright-and-license) + +## Quick start + +Four quick start options are available: + +- [Download the latest release](https://github.com/twbs/bootstrap/archive/v3.3.0.zip). +- Clone the repo: `git clone https://github.com/twbs/bootstrap.git`. +- Install with [Bower](http://bower.io): `bower install bootstrap`. +- Install with [npm](https://www.npmjs.org): `npm install bootstrap`. + +Read the [Getting started page](http://getbootstrap.com/getting-started/) for information on the framework contents, templates and examples, and more. + +### What's included + +Within the download you'll find the following directories and files, logically grouping common assets and providing both compiled and minified variations. You'll see something like this: + +``` +bootstrap/ +├── css/ +│ ├── bootstrap.css +│ ├── bootstrap.min.css +│ ├── bootstrap-theme.css +│ └── bootstrap-theme.min.css +├── js/ +│ ├── bootstrap.js +│ └── bootstrap.min.js +└── fonts/ + ├── glyphicons-halflings-regular.eot + ├── glyphicons-halflings-regular.svg + ├── glyphicons-halflings-regular.ttf + └── glyphicons-halflings-regular.woff +``` + +We provide compiled CSS and JS (`bootstrap.*`), as well as compiled and minified CSS and JS (`bootstrap.min.*`). Fonts from Glyphicons are included, as is the optional Bootstrap theme. + + + +## Bugs and feature requests + +Have a bug or a feature request? Please first read the [issue guidelines](https://github.com/twbs/bootstrap/blob/master/CONTRIBUTING.md#using-the-issue-tracker) and search for existing and closed issues. If your problem or idea is not addressed yet, [please open a new issue](https://github.com/twbs/bootstrap/issues/new). + + +## Documentation + +Bootstrap's documentation, included in this repo in the root directory, is built with [Jekyll](http://jekyllrb.com) and publicly hosted on GitHub Pages at . The docs may also be run locally. + +### Running documentation locally + +1. If necessary, [install Jekyll](http://jekyllrb.com/docs/installation) (requires v2.3.x). + - **Windows users:** Read [this unofficial guide](http://jekyll-windows.juthilo.com/) to get Jekyll up and running without problems. +2. Install the Ruby-based syntax highlighter, [Rouge](https://github.com/jneen/rouge), with `gem install rouge`. +3. From the root `/bootstrap` directory, run `jekyll serve` in the command line. +4. Open in your browser, and voilà. + +Learn more about using Jekyll by reading its [documentation](http://jekyllrb.com/docs/home/). + +### Documentation for previous releases + +Documentation for v2.3.2 has been made available for the time being at while folks transition to Bootstrap 3. + +[Previous releases](https://github.com/twbs/bootstrap/releases) and their documentation are also available for download. + + + +## Contributing + +Please read through our [contributing guidelines](https://github.com/twbs/bootstrap/blob/master/CONTRIBUTING.md). Included are directions for opening issues, coding standards, and notes on development. + +Moreover, if your pull request contains JavaScript patches or features, you must include relevant unit tests. All HTML and CSS should conform to the [Code Guide](https://github.com/mdo/code-guide), maintained by [Mark Otto](https://github.com/mdo). + +Editor preferences are available in the [editor config](https://github.com/twbs/bootstrap/blob/master/.editorconfig) for easy use in common text editors. Read more and download plugins at . + + + +## Community + +Keep track of development and community news. + +- Follow [@twbootstrap on Twitter](https://twitter.com/twbootstrap). +- Read and subscribe to [The Official Bootstrap Blog](http://blog.getbootstrap.com). +- Chat with fellow Bootstrappers in IRC. On the `irc.freenode.net` server, in the `##bootstrap` channel. +- Implementation help may be found at Stack Overflow (tagged [`twitter-bootstrap-3`](http://stackoverflow.com/questions/tagged/twitter-bootstrap-3)). + + + +## Versioning + +For transparency into our release cycle and in striving to maintain backward compatibility, Bootstrap is maintained under [the Semantic Versioning guidelines](http://semver.org/). Sometimes we screw up, but we'll adhere to those rules whenever possible. + + + +## Creators + +**Mark Otto** + +- +- + +**Jacob Thornton** + +- +- + + + +## Copyright and license + +Code and documentation copyright 2011-2014 Twitter, Inc. Code released under [the MIT license](LICENSE). Docs released under [Creative Commons](docs/LICENSE). diff --git a/bower_components/bootstrap/bower.json b/bower_components/bootstrap/bower.json new file mode 100644 index 0000000..e401706 --- /dev/null +++ b/bower_components/bootstrap/bower.json @@ -0,0 +1,38 @@ +{ + "name": "bootstrap", + "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.", + "version": "3.3.0", + "keywords": [ + "css", + "js", + "less", + "mobile-first", + "responsive", + "front-end", + "framework", + "web" + ], + "homepage": "http://getbootstrap.com", + "main": [ + "less/bootstrap.less", + "dist/css/bootstrap.css", + "dist/js/bootstrap.js", + "dist/fonts/glyphicons-halflings-regular.eot", + "dist/fonts/glyphicons-halflings-regular.svg", + "dist/fonts/glyphicons-halflings-regular.ttf", + "dist/fonts/glyphicons-halflings-regular.woff" + ], + "ignore": [ + "/.*", + "_config.yml", + "CNAME", + "composer.json", + "CONTRIBUTING.md", + "docs", + "js/tests", + "test-infra" + ], + "dependencies": { + "jquery": ">= 1.9.1" + } +} diff --git a/bower_components/bootstrap/dist/css/bootstrap-theme.css b/bower_components/bootstrap/dist/css/bootstrap-theme.css new file mode 100644 index 0000000..b82bd72 --- /dev/null +++ b/bower_components/bootstrap/dist/css/bootstrap-theme.css @@ -0,0 +1,457 @@ +/*! + * Bootstrap v3.3.0 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +.btn-default, +.btn-primary, +.btn-success, +.btn-info, +.btn-warning, +.btn-danger { + text-shadow: 0 -1px 0 rgba(0, 0, 0, .2); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); +} +.btn-default:active, +.btn-primary:active, +.btn-success:active, +.btn-info:active, +.btn-warning:active, +.btn-danger:active, +.btn-default.active, +.btn-primary.active, +.btn-success.active, +.btn-info.active, +.btn-warning.active, +.btn-danger.active { + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); +} +.btn-default .badge, +.btn-primary .badge, +.btn-success .badge, +.btn-info .badge, +.btn-warning .badge, +.btn-danger .badge { + text-shadow: none; +} +.btn:active, +.btn.active { + background-image: none; +} +.btn-default { + text-shadow: 0 1px 0 #fff; + background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%); + background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0)); + background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + background-repeat: repeat-x; + border-color: #dbdbdb; + border-color: #ccc; +} +.btn-default:hover, +.btn-default:focus { + background-color: #e0e0e0; + background-position: 0 -15px; +} +.btn-default:active, +.btn-default.active { + background-color: #e0e0e0; + border-color: #dbdbdb; +} +.btn-default:disabled, +.btn-default[disabled] { + background-color: #e0e0e0; + background-image: none; +} +.btn-primary { + background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%); + background-image: -o-linear-gradient(top, #428bca 0%, #2d6ca2 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#2d6ca2)); + background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + background-repeat: repeat-x; + border-color: #2b669a; +} +.btn-primary:hover, +.btn-primary:focus { + background-color: #2d6ca2; + background-position: 0 -15px; +} +.btn-primary:active, +.btn-primary.active { + background-color: #2d6ca2; + border-color: #2b669a; +} +.btn-primary:disabled, +.btn-primary[disabled] { + background-color: #2d6ca2; + background-image: none; +} +.btn-success { + background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); + background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641)); + background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + background-repeat: repeat-x; + border-color: #3e8f3e; +} +.btn-success:hover, +.btn-success:focus { + background-color: #419641; + background-position: 0 -15px; +} +.btn-success:active, +.btn-success.active { + background-color: #419641; + border-color: #3e8f3e; +} +.btn-success:disabled, +.btn-success[disabled] { + background-color: #419641; + background-image: none; +} +.btn-info { + background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); + background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2)); + background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + background-repeat: repeat-x; + border-color: #28a4c9; +} +.btn-info:hover, +.btn-info:focus { + background-color: #2aabd2; + background-position: 0 -15px; +} +.btn-info:active, +.btn-info.active { + background-color: #2aabd2; + border-color: #28a4c9; +} +.btn-info:disabled, +.btn-info[disabled] { + background-color: #2aabd2; + background-image: none; +} +.btn-warning { + background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); + background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316)); + background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + background-repeat: repeat-x; + border-color: #e38d13; +} +.btn-warning:hover, +.btn-warning:focus { + background-color: #eb9316; + background-position: 0 -15px; +} +.btn-warning:active, +.btn-warning.active { + background-color: #eb9316; + border-color: #e38d13; +} +.btn-warning:disabled, +.btn-warning[disabled] { + background-color: #eb9316; + background-image: none; +} +.btn-danger { + background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); + background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a)); + background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + background-repeat: repeat-x; + border-color: #b92c28; +} +.btn-danger:hover, +.btn-danger:focus { + background-color: #c12e2a; + background-position: 0 -15px; +} +.btn-danger:active, +.btn-danger.active { + background-color: #c12e2a; + border-color: #b92c28; +} +.btn-danger:disabled, +.btn-danger[disabled] { + background-color: #c12e2a; + background-image: none; +} +.thumbnail, +.img-thumbnail { + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); + box-shadow: 0 1px 2px rgba(0, 0, 0, .075); +} +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + background-color: #e8e8e8; + background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); + background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); + background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); + background-repeat: repeat-x; +} +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + background-color: #357ebd; + background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); + background-image: -o-linear-gradient(top, #428bca 0%, #357ebd 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#357ebd)); + background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); + background-repeat: repeat-x; +} +.navbar-default { + background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%); + background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8)); + background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + background-repeat: repeat-x; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); +} +.navbar-default .navbar-nav > .open > a, +.navbar-default .navbar-nav > .active > a { + background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); + background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2)); + background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0); + background-repeat: repeat-x; + -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); + box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); +} +.navbar-brand, +.navbar-nav > li > a { + text-shadow: 0 1px 0 rgba(255, 255, 255, .25); +} +.navbar-inverse { + background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%); + background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222)); + background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + background-repeat: repeat-x; +} +.navbar-inverse .navbar-nav > .open > a, +.navbar-inverse .navbar-nav > .active > a { + background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%); + background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f)); + background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0); + background-repeat: repeat-x; + -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); + box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); +} +.navbar-inverse .navbar-brand, +.navbar-inverse .navbar-nav > li > a { + text-shadow: 0 -1px 0 rgba(0, 0, 0, .25); +} +.navbar-static-top, +.navbar-fixed-top, +.navbar-fixed-bottom { + border-radius: 0; +} +.alert { + text-shadow: 0 1px 0 rgba(255, 255, 255, .2); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); +} +.alert-success { + background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); + background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc)); + background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); + background-repeat: repeat-x; + border-color: #b2dba1; +} +.alert-info { + background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); + background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0)); + background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); + background-repeat: repeat-x; + border-color: #9acfea; +} +.alert-warning { + background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); + background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0)); + background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); + background-repeat: repeat-x; + border-color: #f5e79e; +} +.alert-danger { + background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); + background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3)); + background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); + background-repeat: repeat-x; + border-color: #dca7a7; +} +.progress { + background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); + background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5)); + background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); + background-repeat: repeat-x; +} +.progress-bar { + background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%); + background-image: -o-linear-gradient(top, #428bca 0%, #3071a9 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#3071a9)); + background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0); + background-repeat: repeat-x; +} +.progress-bar-success { + background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); + background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44)); + background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); + background-repeat: repeat-x; +} +.progress-bar-info { + background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); + background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5)); + background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); + background-repeat: repeat-x; +} +.progress-bar-warning { + background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); + background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f)); + background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); + background-repeat: repeat-x; +} +.progress-bar-danger { + background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); + background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c)); + background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); + background-repeat: repeat-x; +} +.progress-bar-striped { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); +} +.list-group { + border-radius: 4px; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); + box-shadow: 0 1px 2px rgba(0, 0, 0, .075); +} +.list-group-item.active, +.list-group-item.active:hover, +.list-group-item.active:focus { + text-shadow: 0 -1px 0 #3071a9; + background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%); + background-image: -o-linear-gradient(top, #428bca 0%, #3278b3 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#3278b3)); + background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0); + background-repeat: repeat-x; + border-color: #3278b3; +} +.list-group-item.active .badge, +.list-group-item.active:hover .badge, +.list-group-item.active:focus .badge { + text-shadow: none; +} +.panel { + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05); + box-shadow: 0 1px 2px rgba(0, 0, 0, .05); +} +.panel-default > .panel-heading { + background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); + background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); + background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); + background-repeat: repeat-x; +} +.panel-primary > .panel-heading { + background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); + background-image: -o-linear-gradient(top, #428bca 0%, #357ebd 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#357ebd)); + background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); + background-repeat: repeat-x; +} +.panel-success > .panel-heading { + background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); + background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6)); + background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); + background-repeat: repeat-x; +} +.panel-info > .panel-heading { + background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); + background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3)); + background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); + background-repeat: repeat-x; +} +.panel-warning > .panel-heading { + background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); + background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc)); + background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); + background-repeat: repeat-x; +} +.panel-danger > .panel-heading { + background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); + background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc)); + background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); + background-repeat: repeat-x; +} +.well { + background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); + background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); + background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5)); + background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); + background-repeat: repeat-x; + border-color: #dcdcdc; + -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); + box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); +} +/*# sourceMappingURL=bootstrap-theme.css.map */ diff --git a/bower_components/bootstrap/dist/css/bootstrap-theme.css.map b/bower_components/bootstrap/dist/css/bootstrap-theme.css.map new file mode 100644 index 0000000..1ea032a --- /dev/null +++ b/bower_components/bootstrap/dist/css/bootstrap-theme.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["less/theme.less","less/mixins/vendor-prefixes.less","bootstrap-theme.css","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":"AAcA;;;;;;EAME,0CAAA;ECgDA,6FAAA;EACQ,qFAAA;EC5DT;AFgBC;;;;;;;;;;;;EC2CA,0DAAA;EACQ,kDAAA;EC7CT;AFVD;;;;;;EAiBI,mBAAA;EECH;AFgCC;;EAEE,wBAAA;EE9BH;AFmCD;EGlDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJiCA,6BAAA;EACA,uBAAA;EA+B2C,2BAAA;EAA2B,oBAAA;EExBvE;AFLC;;EAEE,2BAAA;EACA,8BAAA;EEOH;AFJC;;EAEE,2BAAA;EACA,uBAAA;EEMH;AFHC;;EAEE,2BAAA;EACA,wBAAA;EEKH;AFUD;EGnDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJiCA,6BAAA;EACA,uBAAA;EE+BD;AF7BC;;EAEE,2BAAA;EACA,8BAAA;EE+BH;AF5BC;;EAEE,2BAAA;EACA,uBAAA;EE8BH;AF3BC;;EAEE,2BAAA;EACA,wBAAA;EE6BH;AFbD;EGpDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJiCA,6BAAA;EACA,uBAAA;EEuDD;AFrDC;;EAEE,2BAAA;EACA,8BAAA;EEuDH;AFpDC;;EAEE,2BAAA;EACA,uBAAA;EEsDH;AFnDC;;EAEE,2BAAA;EACA,wBAAA;EEqDH;AFpCD;EGrDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJiCA,6BAAA;EACA,uBAAA;EE+ED;AF7EC;;EAEE,2BAAA;EACA,8BAAA;EE+EH;AF5EC;;EAEE,2BAAA;EACA,uBAAA;EE8EH;AF3EC;;EAEE,2BAAA;EACA,wBAAA;EE6EH;AF3DD;EGtDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJiCA,6BAAA;EACA,uBAAA;EEuGD;AFrGC;;EAEE,2BAAA;EACA,8BAAA;EEuGH;AFpGC;;EAEE,2BAAA;EACA,uBAAA;EEsGH;AFnGC;;EAEE,2BAAA;EACA,wBAAA;EEqGH;AFlFD;EGvDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJiCA,6BAAA;EACA,uBAAA;EE+HD;AF7HC;;EAEE,2BAAA;EACA,8BAAA;EE+HH;AF5HC;;EAEE,2BAAA;EACA,uBAAA;EE8HH;AF3HC;;EAEE,2BAAA;EACA,wBAAA;EE6HH;AFnGD;;ECfE,oDAAA;EACQ,4CAAA;ECsHT;AF9FD;;EGxEI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHuEF,2BAAA;EEoGD;AFlGD;;;EG7EI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH6EF,2BAAA;EEwGD;AF/FD;EG1FI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ECnBF,qEAAA;EJ4GA,oBAAA;EC9CA,6FAAA;EACQ,qFAAA;ECoJT;AF1GD;;EG1FI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EF2CF,0DAAA;EACQ,kDAAA;EC8JT;AFvGD;;EAEE,gDAAA;EEyGD;AFrGD;EG7GI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ECnBF,qEAAA;EFyOD;AF7GD;;EG7GI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EF2CF,yDAAA;EACQ,iDAAA;ECoLT;AFvHD;;EAYI,2CAAA;EE+GH;AF1GD;;;EAGE,kBAAA;EE4GD;AFnGD;EACE,+CAAA;EC5FA,4FAAA;EACQ,oFAAA;ECkMT;AF3FD;EGvJI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH+IF,uBAAA;EEuGD;AFlGD;EGxJI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH+IF,uBAAA;EE+GD;AFzGD;EGzJI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH+IF,uBAAA;EEuHD;AFhHD;EG1JI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH+IF,uBAAA;EE+HD;AFhHD;EGlKI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDqRH;AF7GD;EG5KI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED4RH;AFnHD;EG7KI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDmSH;AFzHD;EG9KI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED0SH;AF/HD;EG/KI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDiTH;AFrID;EGhLI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDwTH;AFxID;EGnJI,+MAAA;EACA,0MAAA;EACA,uMAAA;ED8RH;AFpID;EACE,oBAAA;EC/IA,oDAAA;EACQ,4CAAA;ECsRT;AFrID;;;EAGE,+BAAA;EGpME,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHkMF,uBAAA;EE2ID;AFhJD;;;EAQI,mBAAA;EE6IH;AFnID;ECpKE,mDAAA;EACQ,2CAAA;EC0ST;AF7HD;EG7NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED6VH;AFnID;EG9NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDoWH;AFzID;EG/NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED2WH;AF/ID;EGhOI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDkXH;AFrJD;EGjOI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDyXH;AF3JD;EGlOI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDgYH;AF3JD;EGzOI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHuOF,uBAAA;EC5LA,2FAAA;EACQ,mFAAA;EC8VT","file":"bootstrap-theme.css","sourcesContent":["\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0,0,0,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n // Reset the shadow\n &:active,\n &.active {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n\n .badge {\n text-shadow: none;\n }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners\n background-repeat: repeat-x;\n border-color: darken(@btn-color, 14%);\n\n &:hover,\n &:focus {\n background-color: darken(@btn-color, 12%);\n background-position: 0 -15px;\n }\n\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n border-color: darken(@btn-color, 14%);\n }\n\n &:disabled,\n &[disabled] {\n background-color: darken(@btn-color, 12%);\n background-image: none;\n }\n}\n\n// Common styles\n.btn {\n // Remove the gradient for the pressed/active state\n &:active,\n &.active {\n background-image: none;\n }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger { .btn-styles(@btn-danger-bg); }\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n border-radius: @navbar-border-radius;\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: darken(@navbar-default-link-active-bg, 5%); @end-color: darken(@navbar-default-link-active-bg, 2%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: @navbar-inverse-link-active-bg; @end-color: lighten(@navbar-inverse-link-active-bg, 2.5%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n }\n\n .navbar-brand,\n .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n text-shadow: 0 1px 0 rgba(255,255,255,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success { .alert-styles(@alert-success-bg); }\n.alert-info { .alert-styles(@alert-info-bg); }\n.alert-warning { .alert-styles(@alert-warning-bg); }\n.alert-danger { .alert-styles(@alert-danger-bg); }\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); }\n\n// Reset the striped class because our mixins don't do multiple gradients and\n// the above custom styles override the new `.progress-bar-striped` in v3.2.0.\n.progress-bar-striped {\n #gradient > .striped();\n}\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n border-radius: @border-radius-base;\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n border-color: darken(@list-group-active-border, 7.5%);\n\n .badge {\n text-shadow: none;\n }\n}\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n border-color: darken(@well-bg, 10%);\n @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They will be removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility){\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n // Firefox\n &::-moz-placeholder {\n color: @color;\n opacity: 1; // See https://github.com/twbs/bootstrap/pull/11526\n }\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n",".btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.btn-default:active,\n.btn-primary:active,\n.btn-success:active,\n.btn-info:active,\n.btn-warning:active,\n.btn-danger:active,\n.btn-default.active,\n.btn-primary.active,\n.btn-success.active,\n.btn-info.active,\n.btn-warning.active,\n.btn-danger.active {\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-default .badge,\n.btn-primary .badge,\n.btn-success .badge,\n.btn-info .badge,\n.btn-warning .badge,\n.btn-danger .badge {\n text-shadow: none;\n}\n.btn:active,\n.btn.active {\n background-image: none;\n}\n.btn-default {\n background-image: -webkit-linear-gradient(top, #ffffff 0%, #e0e0e0 100%);\n background-image: -o-linear-gradient(top, #ffffff 0%, #e0e0e0 100%);\n background-image: linear-gradient(to bottom, #ffffff 0%, #e0e0e0 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #dbdbdb;\n text-shadow: 0 1px 0 #fff;\n border-color: #ccc;\n}\n.btn-default:hover,\n.btn-default:focus {\n background-color: #e0e0e0;\n background-position: 0 -15px;\n}\n.btn-default:active,\n.btn-default.active {\n background-color: #e0e0e0;\n border-color: #dbdbdb;\n}\n.btn-default:disabled,\n.btn-default[disabled] {\n background-color: #e0e0e0;\n background-image: none;\n}\n.btn-primary {\n background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%);\n background-image: -o-linear-gradient(top, #428bca 0%, #2d6ca2 100%);\n background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #2b669a;\n}\n.btn-primary:hover,\n.btn-primary:focus {\n background-color: #2d6ca2;\n background-position: 0 -15px;\n}\n.btn-primary:active,\n.btn-primary.active {\n background-color: #2d6ca2;\n border-color: #2b669a;\n}\n.btn-primary:disabled,\n.btn-primary[disabled] {\n background-color: #2d6ca2;\n background-image: none;\n}\n.btn-success {\n background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);\n background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);\n background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #3e8f3e;\n}\n.btn-success:hover,\n.btn-success:focus {\n background-color: #419641;\n background-position: 0 -15px;\n}\n.btn-success:active,\n.btn-success.active {\n background-color: #419641;\n border-color: #3e8f3e;\n}\n.btn-success:disabled,\n.btn-success[disabled] {\n background-color: #419641;\n background-image: none;\n}\n.btn-info {\n background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #28a4c9;\n}\n.btn-info:hover,\n.btn-info:focus {\n background-color: #2aabd2;\n background-position: 0 -15px;\n}\n.btn-info:active,\n.btn-info.active {\n background-color: #2aabd2;\n border-color: #28a4c9;\n}\n.btn-info:disabled,\n.btn-info[disabled] {\n background-color: #2aabd2;\n background-image: none;\n}\n.btn-warning {\n background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #e38d13;\n}\n.btn-warning:hover,\n.btn-warning:focus {\n background-color: #eb9316;\n background-position: 0 -15px;\n}\n.btn-warning:active,\n.btn-warning.active {\n background-color: #eb9316;\n border-color: #e38d13;\n}\n.btn-warning:disabled,\n.btn-warning[disabled] {\n background-color: #eb9316;\n background-image: none;\n}\n.btn-danger {\n background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #b92c28;\n}\n.btn-danger:hover,\n.btn-danger:focus {\n background-color: #c12e2a;\n background-position: 0 -15px;\n}\n.btn-danger:active,\n.btn-danger.active {\n background-color: #c12e2a;\n border-color: #b92c28;\n}\n.btn-danger:disabled,\n.btn-danger[disabled] {\n background-color: #c12e2a;\n background-image: none;\n}\n.thumbnail,\n.img-thumbnail {\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n background-color: #e8e8e8;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);\n background-image: -o-linear-gradient(top, #428bca 0%, #357ebd 100%);\n background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);\n background-color: #357ebd;\n}\n.navbar-default {\n background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);\n background-image: -o-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);\n background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .active > a {\n background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);\n -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);\n}\n.navbar-inverse {\n background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222222 100%);\n background-image: -o-linear-gradient(top, #3c3c3c 0%, #222222 100%);\n background-image: linear-gradient(to bottom, #3c3c3c 0%, #222222 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .active > a {\n background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);\n -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n}\n.navbar-inverse .navbar-brand,\n.navbar-inverse .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n.alert {\n text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n.alert-success {\n background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);\n border-color: #b2dba1;\n}\n.alert-info {\n background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);\n border-color: #9acfea;\n}\n.alert-warning {\n background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);\n border-color: #f5e79e;\n}\n.alert-danger {\n background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);\n border-color: #dca7a7;\n}\n.progress {\n background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);\n}\n.progress-bar {\n background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%);\n background-image: -o-linear-gradient(top, #428bca 0%, #3071a9 100%);\n background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);\n}\n.progress-bar-success {\n background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);\n}\n.progress-bar-info {\n background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);\n}\n.progress-bar-warning {\n background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);\n}\n.progress-bar-danger {\n background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);\n}\n.progress-bar-striped {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.list-group {\n border-radius: 4px;\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 #3071a9;\n background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%);\n background-image: -o-linear-gradient(top, #428bca 0%, #3278b3 100%);\n background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);\n border-color: #3278b3;\n}\n.list-group-item.active .badge,\n.list-group-item.active:hover .badge,\n.list-group-item.active:focus .badge {\n text-shadow: none;\n}\n.panel {\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n.panel-default > .panel-heading {\n background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n}\n.panel-primary > .panel-heading {\n background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);\n background-image: -o-linear-gradient(top, #428bca 0%, #357ebd 100%);\n background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);\n}\n.panel-success > .panel-heading {\n background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);\n}\n.panel-info > .panel-heading {\n background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);\n}\n.panel-warning > .panel-heading {\n background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);\n}\n.panel-danger > .panel-heading {\n background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);\n}\n.well {\n background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);\n border-color: #dcdcdc;\n -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n}\n/*# sourceMappingURL=bootstrap-theme.css.map */","// Gradients\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n"]} \ No newline at end of file diff --git a/bower_components/bootstrap/dist/css/bootstrap-theme.min.css b/bower_components/bootstrap/dist/css/bootstrap-theme.min.css new file mode 100644 index 0000000..3bbb050 --- /dev/null +++ b/bower_components/bootstrap/dist/css/bootstrap-theme.min.css @@ -0,0 +1,5 @@ +/*! + * Bootstrap v3.3.0 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-default .badge,.btn-primary .badge,.btn-success .badge,.btn-info .badge,.btn-warning .badge,.btn-danger .badge{text-shadow:none}.btn:active,.btn.active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default:disabled,.btn-default[disabled]{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:-o-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#2d6ca2));background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#2b669a}.btn-primary:hover,.btn-primary:focus{background-color:#2d6ca2;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#2d6ca2;border-color:#2b669a}.btn-primary:disabled,.btn-primary[disabled]{background-color:#2d6ca2;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-success:disabled,.btn-success[disabled]{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.btn-info:disabled,.btn-info[disabled]{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-warning:disabled,.btn-warning[disabled]{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.btn-danger:disabled,.btn-danger[disabled]{background-color:#c12e2a;background-image:none}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-color:#357ebd;background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-o-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#357ebd));background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-o-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#3071a9));background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-o-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#3278b3));background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);background-repeat:repeat-x;border-color:#3278b3}.list-group-item.active .badge,.list-group-item.active:hover .badge,.list-group-item.active:focus .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-o-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#357ebd));background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} \ No newline at end of file diff --git a/bower_components/bootstrap/dist/css/bootstrap.css b/bower_components/bootstrap/dist/css/bootstrap.css new file mode 100644 index 0000000..4165d41 --- /dev/null +++ b/bower_components/bootstrap/dist/css/bootstrap.css @@ -0,0 +1,6358 @@ +/*! + * Bootstrap v3.3.0 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ +html { + font-family: sans-serif; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +body { + margin: 0; +} +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section, +summary { + display: block; +} +audio, +canvas, +progress, +video { + display: inline-block; + vertical-align: baseline; +} +audio:not([controls]) { + display: none; + height: 0; +} +[hidden], +template { + display: none; +} +a { + background-color: transparent; +} +a:active, +a:hover { + outline: 0; +} +abbr[title] { + border-bottom: 1px dotted; +} +b, +strong { + font-weight: bold; +} +dfn { + font-style: italic; +} +h1 { + margin: .67em 0; + font-size: 2em; +} +mark { + color: #000; + background: #ff0; +} +small { + font-size: 80%; +} +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -.5em; +} +sub { + bottom: -.25em; +} +img { + border: 0; +} +svg:not(:root) { + overflow: hidden; +} +figure { + margin: 1em 40px; +} +hr { + height: 0; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +pre { + overflow: auto; +} +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} +button, +input, +optgroup, +select, +textarea { + margin: 0; + font: inherit; + color: inherit; +} +button { + overflow: visible; +} +button, +select { + text-transform: none; +} +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; + cursor: pointer; +} +button[disabled], +html input[disabled] { + cursor: default; +} +button::-moz-focus-inner, +input::-moz-focus-inner { + padding: 0; + border: 0; +} +input { + line-height: normal; +} +input[type="checkbox"], +input[type="radio"] { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + padding: 0; +} +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} +input[type="search"] { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + -webkit-appearance: textfield; +} +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} +fieldset { + padding: .35em .625em .75em; + margin: 0 2px; + border: 1px solid #c0c0c0; +} +legend { + padding: 0; + border: 0; +} +textarea { + overflow: auto; +} +optgroup { + font-weight: bold; +} +table { + border-spacing: 0; + border-collapse: collapse; +} +td, +th { + padding: 0; +} +/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */ +@media print { + *, + *:before, + *:after { + color: #000 !important; + text-shadow: none !important; + background: transparent !important; + -webkit-box-shadow: none !important; + box-shadow: none !important; + } + a, + a:visited { + text-decoration: underline; + } + a[href]:after { + content: " (" attr(href) ")"; + } + abbr[title]:after { + content: " (" attr(title) ")"; + } + a[href^="#"]:after, + a[href^="javascript:"]:after { + content: ""; + } + pre, + blockquote { + border: 1px solid #999; + + page-break-inside: avoid; + } + thead { + display: table-header-group; + } + tr, + img { + page-break-inside: avoid; + } + img { + max-width: 100% !important; + } + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + h2, + h3 { + page-break-after: avoid; + } + select { + background: #fff !important; + } + .navbar { + display: none; + } + .btn > .caret, + .dropup > .btn > .caret { + border-top-color: #000 !important; + } + .label { + border: 1px solid #000; + } + .table { + border-collapse: collapse !important; + } + .table td, + .table th { + background-color: #fff !important; + } + .table-bordered th, + .table-bordered td { + border: 1px solid #ddd !important; + } +} +@font-face { + font-family: 'Glyphicons Halflings'; + + src: url('../fonts/glyphicons-halflings-regular.eot'); + src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); +} +.glyphicon { + position: relative; + top: 1px; + display: inline-block; + font-family: 'Glyphicons Halflings'; + font-style: normal; + font-weight: normal; + line-height: 1; + + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.glyphicon-asterisk:before { + content: "\2a"; +} +.glyphicon-plus:before { + content: "\2b"; +} +.glyphicon-euro:before, +.glyphicon-eur:before { + content: "\20ac"; +} +.glyphicon-minus:before { + content: "\2212"; +} +.glyphicon-cloud:before { + content: "\2601"; +} +.glyphicon-envelope:before { + content: "\2709"; +} +.glyphicon-pencil:before { + content: "\270f"; +} +.glyphicon-glass:before { + content: "\e001"; +} +.glyphicon-music:before { + content: "\e002"; +} +.glyphicon-search:before { + content: "\e003"; +} +.glyphicon-heart:before { + content: "\e005"; +} +.glyphicon-star:before { + content: "\e006"; +} +.glyphicon-star-empty:before { + content: "\e007"; +} +.glyphicon-user:before { + content: "\e008"; +} +.glyphicon-film:before { + content: "\e009"; +} +.glyphicon-th-large:before { + content: "\e010"; +} +.glyphicon-th:before { + content: "\e011"; +} +.glyphicon-th-list:before { + content: "\e012"; +} +.glyphicon-ok:before { + content: "\e013"; +} +.glyphicon-remove:before { + content: "\e014"; +} +.glyphicon-zoom-in:before { + content: "\e015"; +} +.glyphicon-zoom-out:before { + content: "\e016"; +} +.glyphicon-off:before { + content: "\e017"; +} +.glyphicon-signal:before { + content: "\e018"; +} +.glyphicon-cog:before { + content: "\e019"; +} +.glyphicon-trash:before { + content: "\e020"; +} +.glyphicon-home:before { + content: "\e021"; +} +.glyphicon-file:before { + content: "\e022"; +} +.glyphicon-time:before { + content: "\e023"; +} +.glyphicon-road:before { + content: "\e024"; +} +.glyphicon-download-alt:before { + content: "\e025"; +} +.glyphicon-download:before { + content: "\e026"; +} +.glyphicon-upload:before { + content: "\e027"; +} +.glyphicon-inbox:before { + content: "\e028"; +} +.glyphicon-play-circle:before { + content: "\e029"; +} +.glyphicon-repeat:before { + content: "\e030"; +} +.glyphicon-refresh:before { + content: "\e031"; +} +.glyphicon-list-alt:before { + content: "\e032"; +} +.glyphicon-lock:before { + content: "\e033"; +} +.glyphicon-flag:before { + content: "\e034"; +} +.glyphicon-headphones:before { + content: "\e035"; +} +.glyphicon-volume-off:before { + content: "\e036"; +} +.glyphicon-volume-down:before { + content: "\e037"; +} +.glyphicon-volume-up:before { + content: "\e038"; +} +.glyphicon-qrcode:before { + content: "\e039"; +} +.glyphicon-barcode:before { + content: "\e040"; +} +.glyphicon-tag:before { + content: "\e041"; +} +.glyphicon-tags:before { + content: "\e042"; +} +.glyphicon-book:before { + content: "\e043"; +} +.glyphicon-bookmark:before { + content: "\e044"; +} +.glyphicon-print:before { + content: "\e045"; +} +.glyphicon-camera:before { + content: "\e046"; +} +.glyphicon-font:before { + content: "\e047"; +} +.glyphicon-bold:before { + content: "\e048"; +} +.glyphicon-italic:before { + content: "\e049"; +} +.glyphicon-text-height:before { + content: "\e050"; +} +.glyphicon-text-width:before { + content: "\e051"; +} +.glyphicon-align-left:before { + content: "\e052"; +} +.glyphicon-align-center:before { + content: "\e053"; +} +.glyphicon-align-right:before { + content: "\e054"; +} +.glyphicon-align-justify:before { + content: "\e055"; +} +.glyphicon-list:before { + content: "\e056"; +} +.glyphicon-indent-left:before { + content: "\e057"; +} +.glyphicon-indent-right:before { + content: "\e058"; +} +.glyphicon-facetime-video:before { + content: "\e059"; +} +.glyphicon-picture:before { + content: "\e060"; +} +.glyphicon-map-marker:before { + content: "\e062"; +} +.glyphicon-adjust:before { + content: "\e063"; +} +.glyphicon-tint:before { + content: "\e064"; +} +.glyphicon-edit:before { + content: "\e065"; +} +.glyphicon-share:before { + content: "\e066"; +} +.glyphicon-check:before { + content: "\e067"; +} +.glyphicon-move:before { + content: "\e068"; +} +.glyphicon-step-backward:before { + content: "\e069"; +} +.glyphicon-fast-backward:before { + content: "\e070"; +} +.glyphicon-backward:before { + content: "\e071"; +} +.glyphicon-play:before { + content: "\e072"; +} +.glyphicon-pause:before { + content: "\e073"; +} +.glyphicon-stop:before { + content: "\e074"; +} +.glyphicon-forward:before { + content: "\e075"; +} +.glyphicon-fast-forward:before { + content: "\e076"; +} +.glyphicon-step-forward:before { + content: "\e077"; +} +.glyphicon-eject:before { + content: "\e078"; +} +.glyphicon-chevron-left:before { + content: "\e079"; +} +.glyphicon-chevron-right:before { + content: "\e080"; +} +.glyphicon-plus-sign:before { + content: "\e081"; +} +.glyphicon-minus-sign:before { + content: "\e082"; +} +.glyphicon-remove-sign:before { + content: "\e083"; +} +.glyphicon-ok-sign:before { + content: "\e084"; +} +.glyphicon-question-sign:before { + content: "\e085"; +} +.glyphicon-info-sign:before { + content: "\e086"; +} +.glyphicon-screenshot:before { + content: "\e087"; +} +.glyphicon-remove-circle:before { + content: "\e088"; +} +.glyphicon-ok-circle:before { + content: "\e089"; +} +.glyphicon-ban-circle:before { + content: "\e090"; +} +.glyphicon-arrow-left:before { + content: "\e091"; +} +.glyphicon-arrow-right:before { + content: "\e092"; +} +.glyphicon-arrow-up:before { + content: "\e093"; +} +.glyphicon-arrow-down:before { + content: "\e094"; +} +.glyphicon-share-alt:before { + content: "\e095"; +} +.glyphicon-resize-full:before { + content: "\e096"; +} +.glyphicon-resize-small:before { + content: "\e097"; +} +.glyphicon-exclamation-sign:before { + content: "\e101"; +} +.glyphicon-gift:before { + content: "\e102"; +} +.glyphicon-leaf:before { + content: "\e103"; +} +.glyphicon-fire:before { + content: "\e104"; +} +.glyphicon-eye-open:before { + content: "\e105"; +} +.glyphicon-eye-close:before { + content: "\e106"; +} +.glyphicon-warning-sign:before { + content: "\e107"; +} +.glyphicon-plane:before { + content: "\e108"; +} +.glyphicon-calendar:before { + content: "\e109"; +} +.glyphicon-random:before { + content: "\e110"; +} +.glyphicon-comment:before { + content: "\e111"; +} +.glyphicon-magnet:before { + content: "\e112"; +} +.glyphicon-chevron-up:before { + content: "\e113"; +} +.glyphicon-chevron-down:before { + content: "\e114"; +} +.glyphicon-retweet:before { + content: "\e115"; +} +.glyphicon-shopping-cart:before { + content: "\e116"; +} +.glyphicon-folder-close:before { + content: "\e117"; +} +.glyphicon-folder-open:before { + content: "\e118"; +} +.glyphicon-resize-vertical:before { + content: "\e119"; +} +.glyphicon-resize-horizontal:before { + content: "\e120"; +} +.glyphicon-hdd:before { + content: "\e121"; +} +.glyphicon-bullhorn:before { + content: "\e122"; +} +.glyphicon-bell:before { + content: "\e123"; +} +.glyphicon-certificate:before { + content: "\e124"; +} +.glyphicon-thumbs-up:before { + content: "\e125"; +} +.glyphicon-thumbs-down:before { + content: "\e126"; +} +.glyphicon-hand-right:before { + content: "\e127"; +} +.glyphicon-hand-left:before { + content: "\e128"; +} +.glyphicon-hand-up:before { + content: "\e129"; +} +.glyphicon-hand-down:before { + content: "\e130"; +} +.glyphicon-circle-arrow-right:before { + content: "\e131"; +} +.glyphicon-circle-arrow-left:before { + content: "\e132"; +} +.glyphicon-circle-arrow-up:before { + content: "\e133"; +} +.glyphicon-circle-arrow-down:before { + content: "\e134"; +} +.glyphicon-globe:before { + content: "\e135"; +} +.glyphicon-wrench:before { + content: "\e136"; +} +.glyphicon-tasks:before { + content: "\e137"; +} +.glyphicon-filter:before { + content: "\e138"; +} +.glyphicon-briefcase:before { + content: "\e139"; +} +.glyphicon-fullscreen:before { + content: "\e140"; +} +.glyphicon-dashboard:before { + content: "\e141"; +} +.glyphicon-paperclip:before { + content: "\e142"; +} +.glyphicon-heart-empty:before { + content: "\e143"; +} +.glyphicon-link:before { + content: "\e144"; +} +.glyphicon-phone:before { + content: "\e145"; +} +.glyphicon-pushpin:before { + content: "\e146"; +} +.glyphicon-usd:before { + content: "\e148"; +} +.glyphicon-gbp:before { + content: "\e149"; +} +.glyphicon-sort:before { + content: "\e150"; +} +.glyphicon-sort-by-alphabet:before { + content: "\e151"; +} +.glyphicon-sort-by-alphabet-alt:before { + content: "\e152"; +} +.glyphicon-sort-by-order:before { + content: "\e153"; +} +.glyphicon-sort-by-order-alt:before { + content: "\e154"; +} +.glyphicon-sort-by-attributes:before { + content: "\e155"; +} +.glyphicon-sort-by-attributes-alt:before { + content: "\e156"; +} +.glyphicon-unchecked:before { + content: "\e157"; +} +.glyphicon-expand:before { + content: "\e158"; +} +.glyphicon-collapse-down:before { + content: "\e159"; +} +.glyphicon-collapse-up:before { + content: "\e160"; +} +.glyphicon-log-in:before { + content: "\e161"; +} +.glyphicon-flash:before { + content: "\e162"; +} +.glyphicon-log-out:before { + content: "\e163"; +} +.glyphicon-new-window:before { + content: "\e164"; +} +.glyphicon-record:before { + content: "\e165"; +} +.glyphicon-save:before { + content: "\e166"; +} +.glyphicon-open:before { + content: "\e167"; +} +.glyphicon-saved:before { + content: "\e168"; +} +.glyphicon-import:before { + content: "\e169"; +} +.glyphicon-export:before { + content: "\e170"; +} +.glyphicon-send:before { + content: "\e171"; +} +.glyphicon-floppy-disk:before { + content: "\e172"; +} +.glyphicon-floppy-saved:before { + content: "\e173"; +} +.glyphicon-floppy-remove:before { + content: "\e174"; +} +.glyphicon-floppy-save:before { + content: "\e175"; +} +.glyphicon-floppy-open:before { + content: "\e176"; +} +.glyphicon-credit-card:before { + content: "\e177"; +} +.glyphicon-transfer:before { + content: "\e178"; +} +.glyphicon-cutlery:before { + content: "\e179"; +} +.glyphicon-header:before { + content: "\e180"; +} +.glyphicon-compressed:before { + content: "\e181"; +} +.glyphicon-earphone:before { + content: "\e182"; +} +.glyphicon-phone-alt:before { + content: "\e183"; +} +.glyphicon-tower:before { + content: "\e184"; +} +.glyphicon-stats:before { + content: "\e185"; +} +.glyphicon-sd-video:before { + content: "\e186"; +} +.glyphicon-hd-video:before { + content: "\e187"; +} +.glyphicon-subtitles:before { + content: "\e188"; +} +.glyphicon-sound-stereo:before { + content: "\e189"; +} +.glyphicon-sound-dolby:before { + content: "\e190"; +} +.glyphicon-sound-5-1:before { + content: "\e191"; +} +.glyphicon-sound-6-1:before { + content: "\e192"; +} +.glyphicon-sound-7-1:before { + content: "\e193"; +} +.glyphicon-copyright-mark:before { + content: "\e194"; +} +.glyphicon-registration-mark:before { + content: "\e195"; +} +.glyphicon-cloud-download:before { + content: "\e197"; +} +.glyphicon-cloud-upload:before { + content: "\e198"; +} +.glyphicon-tree-conifer:before { + content: "\e199"; +} +.glyphicon-tree-deciduous:before { + content: "\e200"; +} +* { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +*:before, +*:after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +html { + font-size: 10px; + + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} +body { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + line-height: 1.42857143; + color: #333; + background-color: #fff; +} +input, +button, +select, +textarea { + font-family: inherit; + font-size: inherit; + line-height: inherit; +} +a { + color: #428bca; + text-decoration: none; +} +a:hover, +a:focus { + color: #2a6496; + text-decoration: underline; +} +a:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +figure { + margin: 0; +} +img { + vertical-align: middle; +} +.img-responsive, +.thumbnail > img, +.thumbnail a > img, +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + display: block; + max-width: 100%; + height: auto; +} +.img-rounded { + border-radius: 6px; +} +.img-thumbnail { + display: inline-block; + max-width: 100%; + height: auto; + padding: 4px; + line-height: 1.42857143; + background-color: #fff; + border: 1px solid #ddd; + border-radius: 4px; + -webkit-transition: all .2s ease-in-out; + -o-transition: all .2s ease-in-out; + transition: all .2s ease-in-out; +} +.img-circle { + border-radius: 50%; +} +hr { + margin-top: 20px; + margin-bottom: 20px; + border: 0; + border-top: 1px solid #eee; +} +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; +} +.sr-only-focusable:active, +.sr-only-focusable:focus { + position: static; + width: auto; + height: auto; + margin: 0; + overflow: visible; + clip: auto; +} +h1, +h2, +h3, +h4, +h5, +h6, +.h1, +.h2, +.h3, +.h4, +.h5, +.h6 { + font-family: inherit; + font-weight: 500; + line-height: 1.1; + color: inherit; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small, +.h1 small, +.h2 small, +.h3 small, +.h4 small, +.h5 small, +.h6 small, +h1 .small, +h2 .small, +h3 .small, +h4 .small, +h5 .small, +h6 .small, +.h1 .small, +.h2 .small, +.h3 .small, +.h4 .small, +.h5 .small, +.h6 .small { + font-weight: normal; + line-height: 1; + color: #777; +} +h1, +.h1, +h2, +.h2, +h3, +.h3 { + margin-top: 20px; + margin-bottom: 10px; +} +h1 small, +.h1 small, +h2 small, +.h2 small, +h3 small, +.h3 small, +h1 .small, +.h1 .small, +h2 .small, +.h2 .small, +h3 .small, +.h3 .small { + font-size: 65%; +} +h4, +.h4, +h5, +.h5, +h6, +.h6 { + margin-top: 10px; + margin-bottom: 10px; +} +h4 small, +.h4 small, +h5 small, +.h5 small, +h6 small, +.h6 small, +h4 .small, +.h4 .small, +h5 .small, +.h5 .small, +h6 .small, +.h6 .small { + font-size: 75%; +} +h1, +.h1 { + font-size: 36px; +} +h2, +.h2 { + font-size: 30px; +} +h3, +.h3 { + font-size: 24px; +} +h4, +.h4 { + font-size: 18px; +} +h5, +.h5 { + font-size: 14px; +} +h6, +.h6 { + font-size: 12px; +} +p { + margin: 0 0 10px; +} +.lead { + margin-bottom: 20px; + font-size: 16px; + font-weight: 300; + line-height: 1.4; +} +@media (min-width: 768px) { + .lead { + font-size: 21px; + } +} +small, +.small { + font-size: 85%; +} +mark, +.mark { + padding: .2em; + background-color: #fcf8e3; +} +.text-left { + text-align: left; +} +.text-right { + text-align: right; +} +.text-center { + text-align: center; +} +.text-justify { + text-align: justify; +} +.text-nowrap { + white-space: nowrap; +} +.text-lowercase { + text-transform: lowercase; +} +.text-uppercase { + text-transform: uppercase; +} +.text-capitalize { + text-transform: capitalize; +} +.text-muted { + color: #777; +} +.text-primary { + color: #428bca; +} +a.text-primary:hover { + color: #3071a9; +} +.text-success { + color: #3c763d; +} +a.text-success:hover { + color: #2b542c; +} +.text-info { + color: #31708f; +} +a.text-info:hover { + color: #245269; +} +.text-warning { + color: #8a6d3b; +} +a.text-warning:hover { + color: #66512c; +} +.text-danger { + color: #a94442; +} +a.text-danger:hover { + color: #843534; +} +.bg-primary { + color: #fff; + background-color: #428bca; +} +a.bg-primary:hover { + background-color: #3071a9; +} +.bg-success { + background-color: #dff0d8; +} +a.bg-success:hover { + background-color: #c1e2b3; +} +.bg-info { + background-color: #d9edf7; +} +a.bg-info:hover { + background-color: #afd9ee; +} +.bg-warning { + background-color: #fcf8e3; +} +a.bg-warning:hover { + background-color: #f7ecb5; +} +.bg-danger { + background-color: #f2dede; +} +a.bg-danger:hover { + background-color: #e4b9b9; +} +.page-header { + padding-bottom: 9px; + margin: 40px 0 20px; + border-bottom: 1px solid #eee; +} +ul, +ol { + margin-top: 0; + margin-bottom: 10px; +} +ul ul, +ol ul, +ul ol, +ol ol { + margin-bottom: 0; +} +.list-unstyled { + padding-left: 0; + list-style: none; +} +.list-inline { + padding-left: 0; + margin-left: -5px; + list-style: none; +} +.list-inline > li { + display: inline-block; + padding-right: 5px; + padding-left: 5px; +} +dl { + margin-top: 0; + margin-bottom: 20px; +} +dt, +dd { + line-height: 1.42857143; +} +dt { + font-weight: bold; +} +dd { + margin-left: 0; +} +@media (min-width: 768px) { + .dl-horizontal dt { + float: left; + width: 160px; + overflow: hidden; + clear: left; + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; + } + .dl-horizontal dd { + margin-left: 180px; + } +} +abbr[title], +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted #777; +} +.initialism { + font-size: 90%; + text-transform: uppercase; +} +blockquote { + padding: 10px 20px; + margin: 0 0 20px; + font-size: 17.5px; + border-left: 5px solid #eee; +} +blockquote p:last-child, +blockquote ul:last-child, +blockquote ol:last-child { + margin-bottom: 0; +} +blockquote footer, +blockquote small, +blockquote .small { + display: block; + font-size: 80%; + line-height: 1.42857143; + color: #777; +} +blockquote footer:before, +blockquote small:before, +blockquote .small:before { + content: '\2014 \00A0'; +} +.blockquote-reverse, +blockquote.pull-right { + padding-right: 15px; + padding-left: 0; + text-align: right; + border-right: 5px solid #eee; + border-left: 0; +} +.blockquote-reverse footer:before, +blockquote.pull-right footer:before, +.blockquote-reverse small:before, +blockquote.pull-right small:before, +.blockquote-reverse .small:before, +blockquote.pull-right .small:before { + content: ''; +} +.blockquote-reverse footer:after, +blockquote.pull-right footer:after, +.blockquote-reverse small:after, +blockquote.pull-right small:after, +.blockquote-reverse .small:after, +blockquote.pull-right .small:after { + content: '\00A0 \2014'; +} +address { + margin-bottom: 20px; + font-style: normal; + line-height: 1.42857143; +} +code, +kbd, +pre, +samp { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; +} +code { + padding: 2px 4px; + font-size: 90%; + color: #c7254e; + background-color: #f9f2f4; + border-radius: 4px; +} +kbd { + padding: 2px 4px; + font-size: 90%; + color: #fff; + background-color: #333; + border-radius: 3px; + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25); +} +kbd kbd { + padding: 0; + font-size: 100%; + font-weight: bold; + -webkit-box-shadow: none; + box-shadow: none; +} +pre { + display: block; + padding: 9.5px; + margin: 0 0 10px; + font-size: 13px; + line-height: 1.42857143; + color: #333; + word-break: break-all; + word-wrap: break-word; + background-color: #f5f5f5; + border: 1px solid #ccc; + border-radius: 4px; +} +pre code { + padding: 0; + font-size: inherit; + color: inherit; + white-space: pre-wrap; + background-color: transparent; + border-radius: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +.container { + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} +@media (min-width: 768px) { + .container { + width: 750px; + } +} +@media (min-width: 992px) { + .container { + width: 970px; + } +} +@media (min-width: 1200px) { + .container { + width: 1170px; + } +} +.container-fluid { + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} +.row { + margin-right: -15px; + margin-left: -15px; +} +.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 { + position: relative; + min-height: 1px; + padding-right: 15px; + padding-left: 15px; +} +.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 { + float: left; +} +.col-xs-12 { + width: 100%; +} +.col-xs-11 { + width: 91.66666667%; +} +.col-xs-10 { + width: 83.33333333%; +} +.col-xs-9 { + width: 75%; +} +.col-xs-8 { + width: 66.66666667%; +} +.col-xs-7 { + width: 58.33333333%; +} +.col-xs-6 { + width: 50%; +} +.col-xs-5 { + width: 41.66666667%; +} +.col-xs-4 { + width: 33.33333333%; +} +.col-xs-3 { + width: 25%; +} +.col-xs-2 { + width: 16.66666667%; +} +.col-xs-1 { + width: 8.33333333%; +} +.col-xs-pull-12 { + right: 100%; +} +.col-xs-pull-11 { + right: 91.66666667%; +} +.col-xs-pull-10 { + right: 83.33333333%; +} +.col-xs-pull-9 { + right: 75%; +} +.col-xs-pull-8 { + right: 66.66666667%; +} +.col-xs-pull-7 { + right: 58.33333333%; +} +.col-xs-pull-6 { + right: 50%; +} +.col-xs-pull-5 { + right: 41.66666667%; +} +.col-xs-pull-4 { + right: 33.33333333%; +} +.col-xs-pull-3 { + right: 25%; +} +.col-xs-pull-2 { + right: 16.66666667%; +} +.col-xs-pull-1 { + right: 8.33333333%; +} +.col-xs-pull-0 { + right: auto; +} +.col-xs-push-12 { + left: 100%; +} +.col-xs-push-11 { + left: 91.66666667%; +} +.col-xs-push-10 { + left: 83.33333333%; +} +.col-xs-push-9 { + left: 75%; +} +.col-xs-push-8 { + left: 66.66666667%; +} +.col-xs-push-7 { + left: 58.33333333%; +} +.col-xs-push-6 { + left: 50%; +} +.col-xs-push-5 { + left: 41.66666667%; +} +.col-xs-push-4 { + left: 33.33333333%; +} +.col-xs-push-3 { + left: 25%; +} +.col-xs-push-2 { + left: 16.66666667%; +} +.col-xs-push-1 { + left: 8.33333333%; +} +.col-xs-push-0 { + left: auto; +} +.col-xs-offset-12 { + margin-left: 100%; +} +.col-xs-offset-11 { + margin-left: 91.66666667%; +} +.col-xs-offset-10 { + margin-left: 83.33333333%; +} +.col-xs-offset-9 { + margin-left: 75%; +} +.col-xs-offset-8 { + margin-left: 66.66666667%; +} +.col-xs-offset-7 { + margin-left: 58.33333333%; +} +.col-xs-offset-6 { + margin-left: 50%; +} +.col-xs-offset-5 { + margin-left: 41.66666667%; +} +.col-xs-offset-4 { + margin-left: 33.33333333%; +} +.col-xs-offset-3 { + margin-left: 25%; +} +.col-xs-offset-2 { + margin-left: 16.66666667%; +} +.col-xs-offset-1 { + margin-left: 8.33333333%; +} +.col-xs-offset-0 { + margin-left: 0; +} +@media (min-width: 768px) { + .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 { + float: left; + } + .col-sm-12 { + width: 100%; + } + .col-sm-11 { + width: 91.66666667%; + } + .col-sm-10 { + width: 83.33333333%; + } + .col-sm-9 { + width: 75%; + } + .col-sm-8 { + width: 66.66666667%; + } + .col-sm-7 { + width: 58.33333333%; + } + .col-sm-6 { + width: 50%; + } + .col-sm-5 { + width: 41.66666667%; + } + .col-sm-4 { + width: 33.33333333%; + } + .col-sm-3 { + width: 25%; + } + .col-sm-2 { + width: 16.66666667%; + } + .col-sm-1 { + width: 8.33333333%; + } + .col-sm-pull-12 { + right: 100%; + } + .col-sm-pull-11 { + right: 91.66666667%; + } + .col-sm-pull-10 { + right: 83.33333333%; + } + .col-sm-pull-9 { + right: 75%; + } + .col-sm-pull-8 { + right: 66.66666667%; + } + .col-sm-pull-7 { + right: 58.33333333%; + } + .col-sm-pull-6 { + right: 50%; + } + .col-sm-pull-5 { + right: 41.66666667%; + } + .col-sm-pull-4 { + right: 33.33333333%; + } + .col-sm-pull-3 { + right: 25%; + } + .col-sm-pull-2 { + right: 16.66666667%; + } + .col-sm-pull-1 { + right: 8.33333333%; + } + .col-sm-pull-0 { + right: auto; + } + .col-sm-push-12 { + left: 100%; + } + .col-sm-push-11 { + left: 91.66666667%; + } + .col-sm-push-10 { + left: 83.33333333%; + } + .col-sm-push-9 { + left: 75%; + } + .col-sm-push-8 { + left: 66.66666667%; + } + .col-sm-push-7 { + left: 58.33333333%; + } + .col-sm-push-6 { + left: 50%; + } + .col-sm-push-5 { + left: 41.66666667%; + } + .col-sm-push-4 { + left: 33.33333333%; + } + .col-sm-push-3 { + left: 25%; + } + .col-sm-push-2 { + left: 16.66666667%; + } + .col-sm-push-1 { + left: 8.33333333%; + } + .col-sm-push-0 { + left: auto; + } + .col-sm-offset-12 { + margin-left: 100%; + } + .col-sm-offset-11 { + margin-left: 91.66666667%; + } + .col-sm-offset-10 { + margin-left: 83.33333333%; + } + .col-sm-offset-9 { + margin-left: 75%; + } + .col-sm-offset-8 { + margin-left: 66.66666667%; + } + .col-sm-offset-7 { + margin-left: 58.33333333%; + } + .col-sm-offset-6 { + margin-left: 50%; + } + .col-sm-offset-5 { + margin-left: 41.66666667%; + } + .col-sm-offset-4 { + margin-left: 33.33333333%; + } + .col-sm-offset-3 { + margin-left: 25%; + } + .col-sm-offset-2 { + margin-left: 16.66666667%; + } + .col-sm-offset-1 { + margin-left: 8.33333333%; + } + .col-sm-offset-0 { + margin-left: 0; + } +} +@media (min-width: 992px) { + .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 { + float: left; + } + .col-md-12 { + width: 100%; + } + .col-md-11 { + width: 91.66666667%; + } + .col-md-10 { + width: 83.33333333%; + } + .col-md-9 { + width: 75%; + } + .col-md-8 { + width: 66.66666667%; + } + .col-md-7 { + width: 58.33333333%; + } + .col-md-6 { + width: 50%; + } + .col-md-5 { + width: 41.66666667%; + } + .col-md-4 { + width: 33.33333333%; + } + .col-md-3 { + width: 25%; + } + .col-md-2 { + width: 16.66666667%; + } + .col-md-1 { + width: 8.33333333%; + } + .col-md-pull-12 { + right: 100%; + } + .col-md-pull-11 { + right: 91.66666667%; + } + .col-md-pull-10 { + right: 83.33333333%; + } + .col-md-pull-9 { + right: 75%; + } + .col-md-pull-8 { + right: 66.66666667%; + } + .col-md-pull-7 { + right: 58.33333333%; + } + .col-md-pull-6 { + right: 50%; + } + .col-md-pull-5 { + right: 41.66666667%; + } + .col-md-pull-4 { + right: 33.33333333%; + } + .col-md-pull-3 { + right: 25%; + } + .col-md-pull-2 { + right: 16.66666667%; + } + .col-md-pull-1 { + right: 8.33333333%; + } + .col-md-pull-0 { + right: auto; + } + .col-md-push-12 { + left: 100%; + } + .col-md-push-11 { + left: 91.66666667%; + } + .col-md-push-10 { + left: 83.33333333%; + } + .col-md-push-9 { + left: 75%; + } + .col-md-push-8 { + left: 66.66666667%; + } + .col-md-push-7 { + left: 58.33333333%; + } + .col-md-push-6 { + left: 50%; + } + .col-md-push-5 { + left: 41.66666667%; + } + .col-md-push-4 { + left: 33.33333333%; + } + .col-md-push-3 { + left: 25%; + } + .col-md-push-2 { + left: 16.66666667%; + } + .col-md-push-1 { + left: 8.33333333%; + } + .col-md-push-0 { + left: auto; + } + .col-md-offset-12 { + margin-left: 100%; + } + .col-md-offset-11 { + margin-left: 91.66666667%; + } + .col-md-offset-10 { + margin-left: 83.33333333%; + } + .col-md-offset-9 { + margin-left: 75%; + } + .col-md-offset-8 { + margin-left: 66.66666667%; + } + .col-md-offset-7 { + margin-left: 58.33333333%; + } + .col-md-offset-6 { + margin-left: 50%; + } + .col-md-offset-5 { + margin-left: 41.66666667%; + } + .col-md-offset-4 { + margin-left: 33.33333333%; + } + .col-md-offset-3 { + margin-left: 25%; + } + .col-md-offset-2 { + margin-left: 16.66666667%; + } + .col-md-offset-1 { + margin-left: 8.33333333%; + } + .col-md-offset-0 { + margin-left: 0; + } +} +@media (min-width: 1200px) { + .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 { + float: left; + } + .col-lg-12 { + width: 100%; + } + .col-lg-11 { + width: 91.66666667%; + } + .col-lg-10 { + width: 83.33333333%; + } + .col-lg-9 { + width: 75%; + } + .col-lg-8 { + width: 66.66666667%; + } + .col-lg-7 { + width: 58.33333333%; + } + .col-lg-6 { + width: 50%; + } + .col-lg-5 { + width: 41.66666667%; + } + .col-lg-4 { + width: 33.33333333%; + } + .col-lg-3 { + width: 25%; + } + .col-lg-2 { + width: 16.66666667%; + } + .col-lg-1 { + width: 8.33333333%; + } + .col-lg-pull-12 { + right: 100%; + } + .col-lg-pull-11 { + right: 91.66666667%; + } + .col-lg-pull-10 { + right: 83.33333333%; + } + .col-lg-pull-9 { + right: 75%; + } + .col-lg-pull-8 { + right: 66.66666667%; + } + .col-lg-pull-7 { + right: 58.33333333%; + } + .col-lg-pull-6 { + right: 50%; + } + .col-lg-pull-5 { + right: 41.66666667%; + } + .col-lg-pull-4 { + right: 33.33333333%; + } + .col-lg-pull-3 { + right: 25%; + } + .col-lg-pull-2 { + right: 16.66666667%; + } + .col-lg-pull-1 { + right: 8.33333333%; + } + .col-lg-pull-0 { + right: auto; + } + .col-lg-push-12 { + left: 100%; + } + .col-lg-push-11 { + left: 91.66666667%; + } + .col-lg-push-10 { + left: 83.33333333%; + } + .col-lg-push-9 { + left: 75%; + } + .col-lg-push-8 { + left: 66.66666667%; + } + .col-lg-push-7 { + left: 58.33333333%; + } + .col-lg-push-6 { + left: 50%; + } + .col-lg-push-5 { + left: 41.66666667%; + } + .col-lg-push-4 { + left: 33.33333333%; + } + .col-lg-push-3 { + left: 25%; + } + .col-lg-push-2 { + left: 16.66666667%; + } + .col-lg-push-1 { + left: 8.33333333%; + } + .col-lg-push-0 { + left: auto; + } + .col-lg-offset-12 { + margin-left: 100%; + } + .col-lg-offset-11 { + margin-left: 91.66666667%; + } + .col-lg-offset-10 { + margin-left: 83.33333333%; + } + .col-lg-offset-9 { + margin-left: 75%; + } + .col-lg-offset-8 { + margin-left: 66.66666667%; + } + .col-lg-offset-7 { + margin-left: 58.33333333%; + } + .col-lg-offset-6 { + margin-left: 50%; + } + .col-lg-offset-5 { + margin-left: 41.66666667%; + } + .col-lg-offset-4 { + margin-left: 33.33333333%; + } + .col-lg-offset-3 { + margin-left: 25%; + } + .col-lg-offset-2 { + margin-left: 16.66666667%; + } + .col-lg-offset-1 { + margin-left: 8.33333333%; + } + .col-lg-offset-0 { + margin-left: 0; + } +} +table { + background-color: transparent; +} +caption { + padding-top: 8px; + padding-bottom: 8px; + color: #777; + text-align: left; +} +th { + text-align: left; +} +.table { + width: 100%; + max-width: 100%; + margin-bottom: 20px; +} +.table > thead > tr > th, +.table > tbody > tr > th, +.table > tfoot > tr > th, +.table > thead > tr > td, +.table > tbody > tr > td, +.table > tfoot > tr > td { + padding: 8px; + line-height: 1.42857143; + vertical-align: top; + border-top: 1px solid #ddd; +} +.table > thead > tr > th { + vertical-align: bottom; + border-bottom: 2px solid #ddd; +} +.table > caption + thead > tr:first-child > th, +.table > colgroup + thead > tr:first-child > th, +.table > thead:first-child > tr:first-child > th, +.table > caption + thead > tr:first-child > td, +.table > colgroup + thead > tr:first-child > td, +.table > thead:first-child > tr:first-child > td { + border-top: 0; +} +.table > tbody + tbody { + border-top: 2px solid #ddd; +} +.table .table { + background-color: #fff; +} +.table-condensed > thead > tr > th, +.table-condensed > tbody > tr > th, +.table-condensed > tfoot > tr > th, +.table-condensed > thead > tr > td, +.table-condensed > tbody > tr > td, +.table-condensed > tfoot > tr > td { + padding: 5px; +} +.table-bordered { + border: 1px solid #ddd; +} +.table-bordered > thead > tr > th, +.table-bordered > tbody > tr > th, +.table-bordered > tfoot > tr > th, +.table-bordered > thead > tr > td, +.table-bordered > tbody > tr > td, +.table-bordered > tfoot > tr > td { + border: 1px solid #ddd; +} +.table-bordered > thead > tr > th, +.table-bordered > thead > tr > td { + border-bottom-width: 2px; +} +.table-striped > tbody > tr:nth-child(odd) { + background-color: #f9f9f9; +} +.table-hover > tbody > tr:hover { + background-color: #f5f5f5; +} +table col[class*="col-"] { + position: static; + display: table-column; + float: none; +} +table td[class*="col-"], +table th[class*="col-"] { + position: static; + display: table-cell; + float: none; +} +.table > thead > tr > td.active, +.table > tbody > tr > td.active, +.table > tfoot > tr > td.active, +.table > thead > tr > th.active, +.table > tbody > tr > th.active, +.table > tfoot > tr > th.active, +.table > thead > tr.active > td, +.table > tbody > tr.active > td, +.table > tfoot > tr.active > td, +.table > thead > tr.active > th, +.table > tbody > tr.active > th, +.table > tfoot > tr.active > th { + background-color: #f5f5f5; +} +.table-hover > tbody > tr > td.active:hover, +.table-hover > tbody > tr > th.active:hover, +.table-hover > tbody > tr.active:hover > td, +.table-hover > tbody > tr:hover > .active, +.table-hover > tbody > tr.active:hover > th { + background-color: #e8e8e8; +} +.table > thead > tr > td.success, +.table > tbody > tr > td.success, +.table > tfoot > tr > td.success, +.table > thead > tr > th.success, +.table > tbody > tr > th.success, +.table > tfoot > tr > th.success, +.table > thead > tr.success > td, +.table > tbody > tr.success > td, +.table > tfoot > tr.success > td, +.table > thead > tr.success > th, +.table > tbody > tr.success > th, +.table > tfoot > tr.success > th { + background-color: #dff0d8; +} +.table-hover > tbody > tr > td.success:hover, +.table-hover > tbody > tr > th.success:hover, +.table-hover > tbody > tr.success:hover > td, +.table-hover > tbody > tr:hover > .success, +.table-hover > tbody > tr.success:hover > th { + background-color: #d0e9c6; +} +.table > thead > tr > td.info, +.table > tbody > tr > td.info, +.table > tfoot > tr > td.info, +.table > thead > tr > th.info, +.table > tbody > tr > th.info, +.table > tfoot > tr > th.info, +.table > thead > tr.info > td, +.table > tbody > tr.info > td, +.table > tfoot > tr.info > td, +.table > thead > tr.info > th, +.table > tbody > tr.info > th, +.table > tfoot > tr.info > th { + background-color: #d9edf7; +} +.table-hover > tbody > tr > td.info:hover, +.table-hover > tbody > tr > th.info:hover, +.table-hover > tbody > tr.info:hover > td, +.table-hover > tbody > tr:hover > .info, +.table-hover > tbody > tr.info:hover > th { + background-color: #c4e3f3; +} +.table > thead > tr > td.warning, +.table > tbody > tr > td.warning, +.table > tfoot > tr > td.warning, +.table > thead > tr > th.warning, +.table > tbody > tr > th.warning, +.table > tfoot > tr > th.warning, +.table > thead > tr.warning > td, +.table > tbody > tr.warning > td, +.table > tfoot > tr.warning > td, +.table > thead > tr.warning > th, +.table > tbody > tr.warning > th, +.table > tfoot > tr.warning > th { + background-color: #fcf8e3; +} +.table-hover > tbody > tr > td.warning:hover, +.table-hover > tbody > tr > th.warning:hover, +.table-hover > tbody > tr.warning:hover > td, +.table-hover > tbody > tr:hover > .warning, +.table-hover > tbody > tr.warning:hover > th { + background-color: #faf2cc; +} +.table > thead > tr > td.danger, +.table > tbody > tr > td.danger, +.table > tfoot > tr > td.danger, +.table > thead > tr > th.danger, +.table > tbody > tr > th.danger, +.table > tfoot > tr > th.danger, +.table > thead > tr.danger > td, +.table > tbody > tr.danger > td, +.table > tfoot > tr.danger > td, +.table > thead > tr.danger > th, +.table > tbody > tr.danger > th, +.table > tfoot > tr.danger > th { + background-color: #f2dede; +} +.table-hover > tbody > tr > td.danger:hover, +.table-hover > tbody > tr > th.danger:hover, +.table-hover > tbody > tr.danger:hover > td, +.table-hover > tbody > tr:hover > .danger, +.table-hover > tbody > tr.danger:hover > th { + background-color: #ebcccc; +} +.table-responsive { + min-height: .01%; + overflow-x: auto; +} +@media screen and (max-width: 767px) { + .table-responsive { + width: 100%; + margin-bottom: 15px; + overflow-y: hidden; + -ms-overflow-style: -ms-autohiding-scrollbar; + border: 1px solid #ddd; + } + .table-responsive > .table { + margin-bottom: 0; + } + .table-responsive > .table > thead > tr > th, + .table-responsive > .table > tbody > tr > th, + .table-responsive > .table > tfoot > tr > th, + .table-responsive > .table > thead > tr > td, + .table-responsive > .table > tbody > tr > td, + .table-responsive > .table > tfoot > tr > td { + white-space: nowrap; + } + .table-responsive > .table-bordered { + border: 0; + } + .table-responsive > .table-bordered > thead > tr > th:first-child, + .table-responsive > .table-bordered > tbody > tr > th:first-child, + .table-responsive > .table-bordered > tfoot > tr > th:first-child, + .table-responsive > .table-bordered > thead > tr > td:first-child, + .table-responsive > .table-bordered > tbody > tr > td:first-child, + .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; + } + .table-responsive > .table-bordered > thead > tr > th:last-child, + .table-responsive > .table-bordered > tbody > tr > th:last-child, + .table-responsive > .table-bordered > tfoot > tr > th:last-child, + .table-responsive > .table-bordered > thead > tr > td:last-child, + .table-responsive > .table-bordered > tbody > tr > td:last-child, + .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; + } + .table-responsive > .table-bordered > tbody > tr:last-child > th, + .table-responsive > .table-bordered > tfoot > tr:last-child > th, + .table-responsive > .table-bordered > tbody > tr:last-child > td, + .table-responsive > .table-bordered > tfoot > tr:last-child > td { + border-bottom: 0; + } +} +fieldset { + min-width: 0; + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 20px; + font-size: 21px; + line-height: inherit; + color: #333; + border: 0; + border-bottom: 1px solid #e5e5e5; +} +label { + display: inline-block; + max-width: 100%; + margin-bottom: 5px; + font-weight: bold; +} +input[type="search"] { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px \9; + line-height: normal; +} +input[type="file"] { + display: block; +} +input[type="range"] { + display: block; + width: 100%; +} +select[multiple], +select[size] { + height: auto; +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +output { + display: block; + padding-top: 7px; + font-size: 14px; + line-height: 1.42857143; + color: #555; +} +.form-control { + display: block; + width: 100%; + height: 34px; + padding: 6px 12px; + font-size: 14px; + line-height: 1.42857143; + color: #555; + background-color: #fff; + background-image: none; + border: 1px solid #ccc; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s; + -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; +} +.form-control:focus { + border-color: #66afe9; + outline: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6); + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6); +} +.form-control::-moz-placeholder { + color: #999; + opacity: 1; +} +.form-control:-ms-input-placeholder { + color: #999; +} +.form-control::-webkit-input-placeholder { + color: #999; +} +.form-control[disabled], +.form-control[readonly], +fieldset[disabled] .form-control { + cursor: not-allowed; + background-color: #eee; + opacity: 1; +} +textarea.form-control { + height: auto; +} +input[type="search"] { + -webkit-appearance: none; +} +input[type="date"], +input[type="time"], +input[type="datetime-local"], +input[type="month"] { + line-height: 34px; + line-height: 1.42857143 \0; +} +input[type="date"].input-sm, +input[type="time"].input-sm, +input[type="datetime-local"].input-sm, +input[type="month"].input-sm { + line-height: 30px; + line-height: 1.5 \0; +} +input[type="date"].input-lg, +input[type="time"].input-lg, +input[type="datetime-local"].input-lg, +input[type="month"].input-lg { + line-height: 46px; + line-height: 1.33 \0; +} +_:-ms-fullscreen, +:root input[type="date"], +_:-ms-fullscreen, +:root input[type="time"], +_:-ms-fullscreen, +:root input[type="datetime-local"], +_:-ms-fullscreen, +:root input[type="month"] { + line-height: 1.42857143; +} +_:-ms-fullscreen.input-sm, +:root input[type="date"].input-sm, +_:-ms-fullscreen.input-sm, +:root input[type="time"].input-sm, +_:-ms-fullscreen.input-sm, +:root input[type="datetime-local"].input-sm, +_:-ms-fullscreen.input-sm, +:root input[type="month"].input-sm { + line-height: 1.5; +} +_:-ms-fullscreen.input-lg, +:root input[type="date"].input-lg, +_:-ms-fullscreen.input-lg, +:root input[type="time"].input-lg, +_:-ms-fullscreen.input-lg, +:root input[type="datetime-local"].input-lg, +_:-ms-fullscreen.input-lg, +:root input[type="month"].input-lg { + line-height: 1.33; +} +.form-group { + margin-bottom: 15px; +} +.radio, +.checkbox { + position: relative; + display: block; + margin-top: 10px; + margin-bottom: 10px; +} +.radio label, +.checkbox label { + min-height: 20px; + padding-left: 20px; + margin-bottom: 0; + font-weight: normal; + cursor: pointer; +} +.radio input[type="radio"], +.radio-inline input[type="radio"], +.checkbox input[type="checkbox"], +.checkbox-inline input[type="checkbox"] { + position: absolute; + margin-top: 4px \9; + margin-left: -20px; +} +.radio + .radio, +.checkbox + .checkbox { + margin-top: -5px; +} +.radio-inline, +.checkbox-inline { + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + font-weight: normal; + vertical-align: middle; + cursor: pointer; +} +.radio-inline + .radio-inline, +.checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; +} +input[type="radio"][disabled], +input[type="checkbox"][disabled], +input[type="radio"].disabled, +input[type="checkbox"].disabled, +fieldset[disabled] input[type="radio"], +fieldset[disabled] input[type="checkbox"] { + cursor: not-allowed; +} +.radio-inline.disabled, +.checkbox-inline.disabled, +fieldset[disabled] .radio-inline, +fieldset[disabled] .checkbox-inline { + cursor: not-allowed; +} +.radio.disabled label, +.checkbox.disabled label, +fieldset[disabled] .radio label, +fieldset[disabled] .checkbox label { + cursor: not-allowed; +} +.form-control-static { + padding-top: 7px; + padding-bottom: 7px; + margin-bottom: 0; +} +.form-control-static.input-lg, +.form-control-static.input-sm { + padding-right: 0; + padding-left: 0; +} +.input-sm, +.form-group-sm .form-control { + height: 30px; + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +select.input-sm, +select.form-group-sm .form-control { + height: 30px; + line-height: 30px; +} +textarea.input-sm, +textarea.form-group-sm .form-control, +select[multiple].input-sm, +select[multiple].form-group-sm .form-control { + height: auto; +} +.input-lg, +.form-group-lg .form-control { + height: 46px; + padding: 10px 16px; + font-size: 18px; + line-height: 1.33; + border-radius: 6px; +} +select.input-lg, +select.form-group-lg .form-control { + height: 46px; + line-height: 46px; +} +textarea.input-lg, +textarea.form-group-lg .form-control, +select[multiple].input-lg, +select[multiple].form-group-lg .form-control { + height: auto; +} +.has-feedback { + position: relative; +} +.has-feedback .form-control { + padding-right: 42.5px; +} +.form-control-feedback { + position: absolute; + top: 0; + right: 0; + z-index: 2; + display: block; + width: 34px; + height: 34px; + line-height: 34px; + text-align: center; + pointer-events: none; +} +.input-lg + .form-control-feedback { + width: 46px; + height: 46px; + line-height: 46px; +} +.input-sm + .form-control-feedback { + width: 30px; + height: 30px; + line-height: 30px; +} +.has-success .help-block, +.has-success .control-label, +.has-success .radio, +.has-success .checkbox, +.has-success .radio-inline, +.has-success .checkbox-inline, +.has-success.radio label, +.has-success.checkbox label, +.has-success.radio-inline label, +.has-success.checkbox-inline label { + color: #3c763d; +} +.has-success .form-control { + border-color: #3c763d; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); +} +.has-success .form-control:focus { + border-color: #2b542c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168; +} +.has-success .input-group-addon { + color: #3c763d; + background-color: #dff0d8; + border-color: #3c763d; +} +.has-success .form-control-feedback { + color: #3c763d; +} +.has-warning .help-block, +.has-warning .control-label, +.has-warning .radio, +.has-warning .checkbox, +.has-warning .radio-inline, +.has-warning .checkbox-inline, +.has-warning.radio label, +.has-warning.checkbox label, +.has-warning.radio-inline label, +.has-warning.checkbox-inline label { + color: #8a6d3b; +} +.has-warning .form-control { + border-color: #8a6d3b; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); +} +.has-warning .form-control:focus { + border-color: #66512c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b; +} +.has-warning .input-group-addon { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #8a6d3b; +} +.has-warning .form-control-feedback { + color: #8a6d3b; +} +.has-error .help-block, +.has-error .control-label, +.has-error .radio, +.has-error .checkbox, +.has-error .radio-inline, +.has-error .checkbox-inline, +.has-error.radio label, +.has-error.checkbox label, +.has-error.radio-inline label, +.has-error.checkbox-inline label { + color: #a94442; +} +.has-error .form-control { + border-color: #a94442; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); +} +.has-error .form-control:focus { + border-color: #843534; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483; +} +.has-error .input-group-addon { + color: #a94442; + background-color: #f2dede; + border-color: #a94442; +} +.has-error .form-control-feedback { + color: #a94442; +} +.has-feedback label ~ .form-control-feedback { + top: 25px; +} +.has-feedback label.sr-only ~ .form-control-feedback { + top: 0; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 10px; + color: #737373; +} +@media (min-width: 768px) { + .form-inline .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + .form-inline .form-control-static { + display: inline-block; + } + .form-inline .input-group { + display: inline-table; + vertical-align: middle; + } + .form-inline .input-group .input-group-addon, + .form-inline .input-group .input-group-btn, + .form-inline .input-group .form-control { + width: auto; + } + .form-inline .input-group > .form-control { + width: 100%; + } + .form-inline .control-label { + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .radio, + .form-inline .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .radio label, + .form-inline .checkbox label { + padding-left: 0; + } + .form-inline .radio input[type="radio"], + .form-inline .checkbox input[type="checkbox"] { + position: relative; + margin-left: 0; + } + .form-inline .has-feedback .form-control-feedback { + top: 0; + } +} +.form-horizontal .radio, +.form-horizontal .checkbox, +.form-horizontal .radio-inline, +.form-horizontal .checkbox-inline { + padding-top: 7px; + margin-top: 0; + margin-bottom: 0; +} +.form-horizontal .radio, +.form-horizontal .checkbox { + min-height: 27px; +} +.form-horizontal .form-group { + margin-right: -15px; + margin-left: -15px; +} +@media (min-width: 768px) { + .form-horizontal .control-label { + padding-top: 7px; + margin-bottom: 0; + text-align: right; + } +} +.form-horizontal .has-feedback .form-control-feedback { + right: 15px; +} +@media (min-width: 768px) { + .form-horizontal .form-group-lg .control-label { + padding-top: 14.3px; + } +} +@media (min-width: 768px) { + .form-horizontal .form-group-sm .control-label { + padding-top: 6px; + } +} +.btn { + display: inline-block; + padding: 6px 12px; + margin-bottom: 0; + font-size: 14px; + font-weight: normal; + line-height: 1.42857143; + text-align: center; + white-space: nowrap; + vertical-align: middle; + -ms-touch-action: manipulation; + touch-action: manipulation; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + background-image: none; + border: 1px solid transparent; + border-radius: 4px; +} +.btn:focus, +.btn:active:focus, +.btn.active:focus, +.btn.focus, +.btn:active.focus, +.btn.active.focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn:hover, +.btn:focus, +.btn.focus { + color: #333; + text-decoration: none; +} +.btn:active, +.btn.active { + background-image: none; + outline: 0; + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); +} +.btn.disabled, +.btn[disabled], +fieldset[disabled] .btn { + pointer-events: none; + cursor: not-allowed; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + box-shadow: none; + opacity: .65; +} +.btn-default { + color: #333; + background-color: #fff; + border-color: #ccc; +} +.btn-default:hover, +.btn-default:focus, +.btn-default.focus, +.btn-default:active, +.btn-default.active, +.open > .dropdown-toggle.btn-default { + color: #333; + background-color: #e6e6e6; + border-color: #adadad; +} +.btn-default:active, +.btn-default.active, +.open > .dropdown-toggle.btn-default { + background-image: none; +} +.btn-default.disabled, +.btn-default[disabled], +fieldset[disabled] .btn-default, +.btn-default.disabled:hover, +.btn-default[disabled]:hover, +fieldset[disabled] .btn-default:hover, +.btn-default.disabled:focus, +.btn-default[disabled]:focus, +fieldset[disabled] .btn-default:focus, +.btn-default.disabled.focus, +.btn-default[disabled].focus, +fieldset[disabled] .btn-default.focus, +.btn-default.disabled:active, +.btn-default[disabled]:active, +fieldset[disabled] .btn-default:active, +.btn-default.disabled.active, +.btn-default[disabled].active, +fieldset[disabled] .btn-default.active { + background-color: #fff; + border-color: #ccc; +} +.btn-default .badge { + color: #fff; + background-color: #333; +} +.btn-primary { + color: #fff; + background-color: #428bca; + border-color: #357ebd; +} +.btn-primary:hover, +.btn-primary:focus, +.btn-primary.focus, +.btn-primary:active, +.btn-primary.active, +.open > .dropdown-toggle.btn-primary { + color: #fff; + background-color: #3071a9; + border-color: #285e8e; +} +.btn-primary:active, +.btn-primary.active, +.open > .dropdown-toggle.btn-primary { + background-image: none; +} +.btn-primary.disabled, +.btn-primary[disabled], +fieldset[disabled] .btn-primary, +.btn-primary.disabled:hover, +.btn-primary[disabled]:hover, +fieldset[disabled] .btn-primary:hover, +.btn-primary.disabled:focus, +.btn-primary[disabled]:focus, +fieldset[disabled] .btn-primary:focus, +.btn-primary.disabled.focus, +.btn-primary[disabled].focus, +fieldset[disabled] .btn-primary.focus, +.btn-primary.disabled:active, +.btn-primary[disabled]:active, +fieldset[disabled] .btn-primary:active, +.btn-primary.disabled.active, +.btn-primary[disabled].active, +fieldset[disabled] .btn-primary.active { + background-color: #428bca; + border-color: #357ebd; +} +.btn-primary .badge { + color: #428bca; + background-color: #fff; +} +.btn-success { + color: #fff; + background-color: #5cb85c; + border-color: #4cae4c; +} +.btn-success:hover, +.btn-success:focus, +.btn-success.focus, +.btn-success:active, +.btn-success.active, +.open > .dropdown-toggle.btn-success { + color: #fff; + background-color: #449d44; + border-color: #398439; +} +.btn-success:active, +.btn-success.active, +.open > .dropdown-toggle.btn-success { + background-image: none; +} +.btn-success.disabled, +.btn-success[disabled], +fieldset[disabled] .btn-success, +.btn-success.disabled:hover, +.btn-success[disabled]:hover, +fieldset[disabled] .btn-success:hover, +.btn-success.disabled:focus, +.btn-success[disabled]:focus, +fieldset[disabled] .btn-success:focus, +.btn-success.disabled.focus, +.btn-success[disabled].focus, +fieldset[disabled] .btn-success.focus, +.btn-success.disabled:active, +.btn-success[disabled]:active, +fieldset[disabled] .btn-success:active, +.btn-success.disabled.active, +.btn-success[disabled].active, +fieldset[disabled] .btn-success.active { + background-color: #5cb85c; + border-color: #4cae4c; +} +.btn-success .badge { + color: #5cb85c; + background-color: #fff; +} +.btn-info { + color: #fff; + background-color: #5bc0de; + border-color: #46b8da; +} +.btn-info:hover, +.btn-info:focus, +.btn-info.focus, +.btn-info:active, +.btn-info.active, +.open > .dropdown-toggle.btn-info { + color: #fff; + background-color: #31b0d5; + border-color: #269abc; +} +.btn-info:active, +.btn-info.active, +.open > .dropdown-toggle.btn-info { + background-image: none; +} +.btn-info.disabled, +.btn-info[disabled], +fieldset[disabled] .btn-info, +.btn-info.disabled:hover, +.btn-info[disabled]:hover, +fieldset[disabled] .btn-info:hover, +.btn-info.disabled:focus, +.btn-info[disabled]:focus, +fieldset[disabled] .btn-info:focus, +.btn-info.disabled.focus, +.btn-info[disabled].focus, +fieldset[disabled] .btn-info.focus, +.btn-info.disabled:active, +.btn-info[disabled]:active, +fieldset[disabled] .btn-info:active, +.btn-info.disabled.active, +.btn-info[disabled].active, +fieldset[disabled] .btn-info.active { + background-color: #5bc0de; + border-color: #46b8da; +} +.btn-info .badge { + color: #5bc0de; + background-color: #fff; +} +.btn-warning { + color: #fff; + background-color: #f0ad4e; + border-color: #eea236; +} +.btn-warning:hover, +.btn-warning:focus, +.btn-warning.focus, +.btn-warning:active, +.btn-warning.active, +.open > .dropdown-toggle.btn-warning { + color: #fff; + background-color: #ec971f; + border-color: #d58512; +} +.btn-warning:active, +.btn-warning.active, +.open > .dropdown-toggle.btn-warning { + background-image: none; +} +.btn-warning.disabled, +.btn-warning[disabled], +fieldset[disabled] .btn-warning, +.btn-warning.disabled:hover, +.btn-warning[disabled]:hover, +fieldset[disabled] .btn-warning:hover, +.btn-warning.disabled:focus, +.btn-warning[disabled]:focus, +fieldset[disabled] .btn-warning:focus, +.btn-warning.disabled.focus, +.btn-warning[disabled].focus, +fieldset[disabled] .btn-warning.focus, +.btn-warning.disabled:active, +.btn-warning[disabled]:active, +fieldset[disabled] .btn-warning:active, +.btn-warning.disabled.active, +.btn-warning[disabled].active, +fieldset[disabled] .btn-warning.active { + background-color: #f0ad4e; + border-color: #eea236; +} +.btn-warning .badge { + color: #f0ad4e; + background-color: #fff; +} +.btn-danger { + color: #fff; + background-color: #d9534f; + border-color: #d43f3a; +} +.btn-danger:hover, +.btn-danger:focus, +.btn-danger.focus, +.btn-danger:active, +.btn-danger.active, +.open > .dropdown-toggle.btn-danger { + color: #fff; + background-color: #c9302c; + border-color: #ac2925; +} +.btn-danger:active, +.btn-danger.active, +.open > .dropdown-toggle.btn-danger { + background-image: none; +} +.btn-danger.disabled, +.btn-danger[disabled], +fieldset[disabled] .btn-danger, +.btn-danger.disabled:hover, +.btn-danger[disabled]:hover, +fieldset[disabled] .btn-danger:hover, +.btn-danger.disabled:focus, +.btn-danger[disabled]:focus, +fieldset[disabled] .btn-danger:focus, +.btn-danger.disabled.focus, +.btn-danger[disabled].focus, +fieldset[disabled] .btn-danger.focus, +.btn-danger.disabled:active, +.btn-danger[disabled]:active, +fieldset[disabled] .btn-danger:active, +.btn-danger.disabled.active, +.btn-danger[disabled].active, +fieldset[disabled] .btn-danger.active { + background-color: #d9534f; + border-color: #d43f3a; +} +.btn-danger .badge { + color: #d9534f; + background-color: #fff; +} +.btn-link { + font-weight: normal; + color: #428bca; + border-radius: 0; +} +.btn-link, +.btn-link:active, +.btn-link.active, +.btn-link[disabled], +fieldset[disabled] .btn-link { + background-color: transparent; + -webkit-box-shadow: none; + box-shadow: none; +} +.btn-link, +.btn-link:hover, +.btn-link:focus, +.btn-link:active { + border-color: transparent; +} +.btn-link:hover, +.btn-link:focus { + color: #2a6496; + text-decoration: underline; + background-color: transparent; +} +.btn-link[disabled]:hover, +fieldset[disabled] .btn-link:hover, +.btn-link[disabled]:focus, +fieldset[disabled] .btn-link:focus { + color: #777; + text-decoration: none; +} +.btn-lg, +.btn-group-lg > .btn { + padding: 10px 16px; + font-size: 18px; + line-height: 1.33; + border-radius: 6px; +} +.btn-sm, +.btn-group-sm > .btn { + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +.btn-xs, +.btn-group-xs > .btn { + padding: 1px 5px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +.btn-block { + display: block; + width: 100%; +} +.btn-block + .btn-block { + margin-top: 5px; +} +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} +.fade { + opacity: 0; + -webkit-transition: opacity .15s linear; + -o-transition: opacity .15s linear; + transition: opacity .15s linear; +} +.fade.in { + opacity: 1; +} +.collapse { + display: none; + visibility: hidden; +} +.collapse.in { + display: block; + visibility: visible; +} +tr.collapse.in { + display: table-row; +} +tbody.collapse.in { + display: table-row-group; +} +.collapsing { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition-timing-function: ease; + -o-transition-timing-function: ease; + transition-timing-function: ease; + -webkit-transition-duration: .35s; + -o-transition-duration: .35s; + transition-duration: .35s; + -webkit-transition-property: height, visibility; + -o-transition-property: height, visibility; + transition-property: height, visibility; +} +.caret { + display: inline-block; + width: 0; + height: 0; + margin-left: 2px; + vertical-align: middle; + border-top: 4px solid; + border-right: 4px solid transparent; + border-left: 4px solid transparent; +} +.dropdown { + position: relative; +} +.dropdown-toggle:focus { + outline: 0; +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; + font-size: 14px; + text-align: left; + list-style: none; + background-color: #fff; + -webkit-background-clip: padding-box; + background-clip: padding-box; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, .15); + border-radius: 4px; + -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175); + box-shadow: 0 6px 12px rgba(0, 0, 0, .175); +} +.dropdown-menu.pull-right { + right: 0; + left: auto; +} +.dropdown-menu .divider { + height: 1px; + margin: 9px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.dropdown-menu > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 1.42857143; + color: #333; + white-space: nowrap; +} +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + color: #262626; + text-decoration: none; + background-color: #f5f5f5; +} +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + color: #fff; + text-decoration: none; + background-color: #428bca; + outline: 0; +} +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: #777; +} +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + text-decoration: none; + cursor: not-allowed; + background-color: transparent; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.open > .dropdown-menu { + display: block; +} +.open > a { + outline: 0; +} +.dropdown-menu-right { + right: 0; + left: auto; +} +.dropdown-menu-left { + right: auto; + left: 0; +} +.dropdown-header { + display: block; + padding: 3px 20px; + font-size: 12px; + line-height: 1.42857143; + color: #777; + white-space: nowrap; +} +.dropdown-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 990; +} +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + content: ""; + border-top: 0; + border-bottom: 4px solid; +} +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 1px; +} +@media (min-width: 768px) { + .navbar-right .dropdown-menu { + right: 0; + left: auto; + } + .navbar-right .dropdown-menu-left { + right: auto; + left: 0; + } +} +.btn-group, +.btn-group-vertical { + position: relative; + display: inline-block; + vertical-align: middle; +} +.btn-group > .btn, +.btn-group-vertical > .btn { + position: relative; + float: left; +} +.btn-group > .btn:hover, +.btn-group-vertical > .btn:hover, +.btn-group > .btn:focus, +.btn-group-vertical > .btn:focus, +.btn-group > .btn:active, +.btn-group-vertical > .btn:active, +.btn-group > .btn.active, +.btn-group-vertical > .btn.active { + z-index: 2; +} +.btn-group > .btn:focus, +.btn-group-vertical > .btn:focus { + outline: 0; +} +.btn-group .btn + .btn, +.btn-group .btn + .btn-group, +.btn-group .btn-group + .btn, +.btn-group .btn-group + .btn-group { + margin-left: -1px; +} +.btn-toolbar { + margin-left: -5px; +} +.btn-toolbar .btn-group, +.btn-toolbar .input-group { + float: left; +} +.btn-toolbar > .btn, +.btn-toolbar > .btn-group, +.btn-toolbar > .input-group { + margin-left: 5px; +} +.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) { + border-radius: 0; +} +.btn-group > .btn:first-child { + margin-left: 0; +} +.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.btn-group > .btn:last-child:not(:first-child), +.btn-group > .dropdown-toggle:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group > .btn-group { + float: left; +} +.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group > .btn-group:first-child > .btn:last-child, +.btn-group > .btn-group:first-child > .dropdown-toggle { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.btn-group > .btn-group:last-child > .btn:first-child { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} +.btn-group > .btn + .dropdown-toggle { + padding-right: 8px; + padding-left: 8px; +} +.btn-group > .btn-lg + .dropdown-toggle { + padding-right: 12px; + padding-left: 12px; +} +.btn-group.open .dropdown-toggle { + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); +} +.btn-group.open .dropdown-toggle.btn-link { + -webkit-box-shadow: none; + box-shadow: none; +} +.btn .caret { + margin-left: 0; +} +.btn-lg .caret { + border-width: 5px 5px 0; + border-bottom-width: 0; +} +.dropup .btn-lg .caret { + border-width: 0 5px 5px; +} +.btn-group-vertical > .btn, +.btn-group-vertical > .btn-group, +.btn-group-vertical > .btn-group > .btn { + display: block; + float: none; + width: 100%; + max-width: 100%; +} +.btn-group-vertical > .btn-group > .btn { + float: none; +} +.btn-group-vertical > .btn + .btn, +.btn-group-vertical > .btn + .btn-group, +.btn-group-vertical > .btn-group + .btn, +.btn-group-vertical > .btn-group + .btn-group { + margin-top: -1px; + margin-left: 0; +} +.btn-group-vertical > .btn:not(:first-child):not(:last-child) { + border-radius: 0; +} +.btn-group-vertical > .btn:first-child:not(:last-child) { + border-top-right-radius: 4px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn:last-child:not(:first-child) { + border-top-left-radius: 0; + border-top-right-radius: 0; + border-bottom-left-radius: 4px; +} +.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child, +.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child { + border-top-left-radius: 0; + border-top-right-radius: 0; +} +.btn-group-justified { + display: table; + width: 100%; + table-layout: fixed; + border-collapse: separate; +} +.btn-group-justified > .btn, +.btn-group-justified > .btn-group { + display: table-cell; + float: none; + width: 1%; +} +.btn-group-justified > .btn-group .btn { + width: 100%; +} +.btn-group-justified > .btn-group .dropdown-menu { + left: auto; +} +[data-toggle="buttons"] > .btn input[type="radio"], +[data-toggle="buttons"] > .btn-group > .btn input[type="radio"], +[data-toggle="buttons"] > .btn input[type="checkbox"], +[data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] { + position: absolute; + clip: rect(0, 0, 0, 0); + pointer-events: none; +} +.input-group { + position: relative; + display: table; + border-collapse: separate; +} +.input-group[class*="col-"] { + float: none; + padding-right: 0; + padding-left: 0; +} +.input-group .form-control { + position: relative; + z-index: 2; + float: left; + width: 100%; + margin-bottom: 0; +} +.input-group-lg > .form-control, +.input-group-lg > .input-group-addon, +.input-group-lg > .input-group-btn > .btn { + height: 46px; + padding: 10px 16px; + font-size: 18px; + line-height: 1.33; + border-radius: 6px; +} +select.input-group-lg > .form-control, +select.input-group-lg > .input-group-addon, +select.input-group-lg > .input-group-btn > .btn { + height: 46px; + line-height: 46px; +} +textarea.input-group-lg > .form-control, +textarea.input-group-lg > .input-group-addon, +textarea.input-group-lg > .input-group-btn > .btn, +select[multiple].input-group-lg > .form-control, +select[multiple].input-group-lg > .input-group-addon, +select[multiple].input-group-lg > .input-group-btn > .btn { + height: auto; +} +.input-group-sm > .form-control, +.input-group-sm > .input-group-addon, +.input-group-sm > .input-group-btn > .btn { + height: 30px; + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +select.input-group-sm > .form-control, +select.input-group-sm > .input-group-addon, +select.input-group-sm > .input-group-btn > .btn { + height: 30px; + line-height: 30px; +} +textarea.input-group-sm > .form-control, +textarea.input-group-sm > .input-group-addon, +textarea.input-group-sm > .input-group-btn > .btn, +select[multiple].input-group-sm > .form-control, +select[multiple].input-group-sm > .input-group-addon, +select[multiple].input-group-sm > .input-group-btn > .btn { + height: auto; +} +.input-group-addon, +.input-group-btn, +.input-group .form-control { + display: table-cell; +} +.input-group-addon:not(:first-child):not(:last-child), +.input-group-btn:not(:first-child):not(:last-child), +.input-group .form-control:not(:first-child):not(:last-child) { + border-radius: 0; +} +.input-group-addon, +.input-group-btn { + width: 1%; + white-space: nowrap; + vertical-align: middle; +} +.input-group-addon { + padding: 6px 12px; + font-size: 14px; + font-weight: normal; + line-height: 1; + color: #555; + text-align: center; + background-color: #eee; + border: 1px solid #ccc; + border-radius: 4px; +} +.input-group-addon.input-sm { + padding: 5px 10px; + font-size: 12px; + border-radius: 3px; +} +.input-group-addon.input-lg { + padding: 10px 16px; + font-size: 18px; + border-radius: 6px; +} +.input-group-addon input[type="radio"], +.input-group-addon input[type="checkbox"] { + margin-top: 0; +} +.input-group .form-control:first-child, +.input-group-addon:first-child, +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .btn-group > .btn, +.input-group-btn:first-child > .dropdown-toggle, +.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle), +.input-group-btn:last-child > .btn-group:not(:last-child) > .btn { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.input-group-addon:first-child { + border-right: 0; +} +.input-group .form-control:last-child, +.input-group-addon:last-child, +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .btn-group > .btn, +.input-group-btn:last-child > .dropdown-toggle, +.input-group-btn:first-child > .btn:not(:first-child), +.input-group-btn:first-child > .btn-group:not(:first-child) > .btn { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.input-group-addon:last-child { + border-left: 0; +} +.input-group-btn { + position: relative; + font-size: 0; + white-space: nowrap; +} +.input-group-btn > .btn { + position: relative; +} +.input-group-btn > .btn + .btn { + margin-left: -1px; +} +.input-group-btn > .btn:hover, +.input-group-btn > .btn:focus, +.input-group-btn > .btn:active { + z-index: 2; +} +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .btn-group { + margin-right: -1px; +} +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .btn-group { + margin-left: -1px; +} +.nav { + padding-left: 0; + margin-bottom: 0; + list-style: none; +} +.nav > li { + position: relative; + display: block; +} +.nav > li > a { + position: relative; + display: block; + padding: 10px 15px; +} +.nav > li > a:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: #eee; +} +.nav > li.disabled > a { + color: #777; +} +.nav > li.disabled > a:hover, +.nav > li.disabled > a:focus { + color: #777; + text-decoration: none; + cursor: not-allowed; + background-color: transparent; +} +.nav .open > a, +.nav .open > a:hover, +.nav .open > a:focus { + background-color: #eee; + border-color: #428bca; +} +.nav .nav-divider { + height: 1px; + margin: 9px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.nav > li > a > img { + max-width: none; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + float: left; + margin-bottom: -1px; +} +.nav-tabs > li > a { + margin-right: 2px; + line-height: 1.42857143; + border: 1px solid transparent; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eee #eee #ddd; +} +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + color: #555; + cursor: default; + background-color: #fff; + border: 1px solid #ddd; + border-bottom-color: transparent; +} +.nav-tabs.nav-justified { + width: 100%; + border-bottom: 0; +} +.nav-tabs.nav-justified > li { + float: none; +} +.nav-tabs.nav-justified > li > a { + margin-bottom: 5px; + text-align: center; +} +.nav-tabs.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-tabs.nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs.nav-justified > li > a { + margin-right: 0; + border-radius: 4px; +} +.nav-tabs.nav-justified > .active > a, +.nav-tabs.nav-justified > .active > a:hover, +.nav-tabs.nav-justified > .active > a:focus { + border: 1px solid #ddd; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li > a { + border-bottom: 1px solid #ddd; + border-radius: 4px 4px 0 0; + } + .nav-tabs.nav-justified > .active > a, + .nav-tabs.nav-justified > .active > a:hover, + .nav-tabs.nav-justified > .active > a:focus { + border-bottom-color: #fff; + } +} +.nav-pills > li { + float: left; +} +.nav-pills > li > a { + border-radius: 4px; +} +.nav-pills > li + li { + margin-left: 2px; +} +.nav-pills > li.active > a, +.nav-pills > li.active > a:hover, +.nav-pills > li.active > a:focus { + color: #fff; + background-color: #428bca; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li + li { + margin-top: 2px; + margin-left: 0; +} +.nav-justified { + width: 100%; +} +.nav-justified > li { + float: none; +} +.nav-justified > li > a { + margin-bottom: 5px; + text-align: center; +} +.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs-justified { + border-bottom: 0; +} +.nav-tabs-justified > li > a { + margin-right: 0; + border-radius: 4px; +} +.nav-tabs-justified > .active > a, +.nav-tabs-justified > .active > a:hover, +.nav-tabs-justified > .active > a:focus { + border: 1px solid #ddd; +} +@media (min-width: 768px) { + .nav-tabs-justified > li > a { + border-bottom: 1px solid #ddd; + border-radius: 4px 4px 0 0; + } + .nav-tabs-justified > .active > a, + .nav-tabs-justified > .active > a:hover, + .nav-tabs-justified > .active > a:focus { + border-bottom-color: #fff; + } +} +.tab-content > .tab-pane { + display: none; + visibility: hidden; +} +.tab-content > .active { + display: block; + visibility: visible; +} +.nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-left-radius: 0; + border-top-right-radius: 0; +} +.navbar { + position: relative; + min-height: 50px; + margin-bottom: 20px; + border: 1px solid transparent; +} +@media (min-width: 768px) { + .navbar { + border-radius: 4px; + } +} +@media (min-width: 768px) { + .navbar-header { + float: left; + } +} +.navbar-collapse { + padding-right: 15px; + padding-left: 15px; + overflow-x: visible; + -webkit-overflow-scrolling: touch; + border-top: 1px solid transparent; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1); +} +.navbar-collapse.in { + overflow-y: auto; +} +@media (min-width: 768px) { + .navbar-collapse { + width: auto; + border-top: 0; + -webkit-box-shadow: none; + box-shadow: none; + } + .navbar-collapse.collapse { + display: block !important; + height: auto !important; + padding-bottom: 0; + overflow: visible !important; + visibility: visible !important; + } + .navbar-collapse.in { + overflow-y: visible; + } + .navbar-fixed-top .navbar-collapse, + .navbar-static-top .navbar-collapse, + .navbar-fixed-bottom .navbar-collapse { + padding-right: 0; + padding-left: 0; + } +} +.navbar-fixed-top .navbar-collapse, +.navbar-fixed-bottom .navbar-collapse { + max-height: 340px; +} +@media (max-device-width: 480px) and (orientation: landscape) { + .navbar-fixed-top .navbar-collapse, + .navbar-fixed-bottom .navbar-collapse { + max-height: 200px; + } +} +.container > .navbar-header, +.container-fluid > .navbar-header, +.container > .navbar-collapse, +.container-fluid > .navbar-collapse { + margin-right: -15px; + margin-left: -15px; +} +@media (min-width: 768px) { + .container > .navbar-header, + .container-fluid > .navbar-header, + .container > .navbar-collapse, + .container-fluid > .navbar-collapse { + margin-right: 0; + margin-left: 0; + } +} +.navbar-static-top { + z-index: 1000; + border-width: 0 0 1px; +} +@media (min-width: 768px) { + .navbar-static-top { + border-radius: 0; + } +} +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; +} +@media (min-width: 768px) { + .navbar-fixed-top, + .navbar-fixed-bottom { + border-radius: 0; + } +} +.navbar-fixed-top { + top: 0; + border-width: 0 0 1px; +} +.navbar-fixed-bottom { + bottom: 0; + margin-bottom: 0; + border-width: 1px 0 0; +} +.navbar-brand { + float: left; + height: 50px; + padding: 15px 15px; + font-size: 18px; + line-height: 20px; +} +.navbar-brand:hover, +.navbar-brand:focus { + text-decoration: none; +} +.navbar-brand > img { + display: block; +} +@media (min-width: 768px) { + .navbar > .container .navbar-brand, + .navbar > .container-fluid .navbar-brand { + margin-left: -15px; + } +} +.navbar-toggle { + position: relative; + float: right; + padding: 9px 10px; + margin-top: 8px; + margin-right: 15px; + margin-bottom: 8px; + background-color: transparent; + background-image: none; + border: 1px solid transparent; + border-radius: 4px; +} +.navbar-toggle:focus { + outline: 0; +} +.navbar-toggle .icon-bar { + display: block; + width: 22px; + height: 2px; + border-radius: 1px; +} +.navbar-toggle .icon-bar + .icon-bar { + margin-top: 4px; +} +@media (min-width: 768px) { + .navbar-toggle { + display: none; + } +} +.navbar-nav { + margin: 7.5px -15px; +} +.navbar-nav > li > a { + padding-top: 10px; + padding-bottom: 10px; + line-height: 20px; +} +@media (max-width: 767px) { + .navbar-nav .open .dropdown-menu { + position: static; + float: none; + width: auto; + margin-top: 0; + background-color: transparent; + border: 0; + -webkit-box-shadow: none; + box-shadow: none; + } + .navbar-nav .open .dropdown-menu > li > a, + .navbar-nav .open .dropdown-menu .dropdown-header { + padding: 5px 15px 5px 25px; + } + .navbar-nav .open .dropdown-menu > li > a { + line-height: 20px; + } + .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-nav .open .dropdown-menu > li > a:focus { + background-image: none; + } +} +@media (min-width: 768px) { + .navbar-nav { + float: left; + margin: 0; + } + .navbar-nav > li { + float: left; + } + .navbar-nav > li > a { + padding-top: 15px; + padding-bottom: 15px; + } +} +.navbar-form { + padding: 10px 15px; + margin-top: 8px; + margin-right: -15px; + margin-bottom: 8px; + margin-left: -15px; + border-top: 1px solid transparent; + border-bottom: 1px solid transparent; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1); +} +@media (min-width: 768px) { + .navbar-form .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + .navbar-form .form-control-static { + display: inline-block; + } + .navbar-form .input-group { + display: inline-table; + vertical-align: middle; + } + .navbar-form .input-group .input-group-addon, + .navbar-form .input-group .input-group-btn, + .navbar-form .input-group .form-control { + width: auto; + } + .navbar-form .input-group > .form-control { + width: 100%; + } + .navbar-form .control-label { + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .radio, + .navbar-form .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .radio label, + .navbar-form .checkbox label { + padding-left: 0; + } + .navbar-form .radio input[type="radio"], + .navbar-form .checkbox input[type="checkbox"] { + position: relative; + margin-left: 0; + } + .navbar-form .has-feedback .form-control-feedback { + top: 0; + } +} +@media (max-width: 767px) { + .navbar-form .form-group { + margin-bottom: 5px; + } + .navbar-form .form-group:last-child { + margin-bottom: 0; + } +} +@media (min-width: 768px) { + .navbar-form { + width: auto; + padding-top: 0; + padding-bottom: 0; + margin-right: 0; + margin-left: 0; + border: 0; + -webkit-box-shadow: none; + box-shadow: none; + } +} +.navbar-nav > li > .dropdown-menu { + margin-top: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; +} +.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.navbar-btn { + margin-top: 8px; + margin-bottom: 8px; +} +.navbar-btn.btn-sm { + margin-top: 10px; + margin-bottom: 10px; +} +.navbar-btn.btn-xs { + margin-top: 14px; + margin-bottom: 14px; +} +.navbar-text { + margin-top: 15px; + margin-bottom: 15px; +} +@media (min-width: 768px) { + .navbar-text { + float: left; + margin-right: 15px; + margin-left: 15px; + } +} +@media (min-width: 768px) { + .navbar-left { + float: left !important; + } + .navbar-right { + float: right !important; + margin-right: -15px; + } + .navbar-right ~ .navbar-right { + margin-right: 0; + } +} +.navbar-default { + background-color: #f8f8f8; + border-color: #e7e7e7; +} +.navbar-default .navbar-brand { + color: #777; +} +.navbar-default .navbar-brand:hover, +.navbar-default .navbar-brand:focus { + color: #5e5e5e; + background-color: transparent; +} +.navbar-default .navbar-text { + color: #777; +} +.navbar-default .navbar-nav > li > a { + color: #777; +} +.navbar-default .navbar-nav > li > a:hover, +.navbar-default .navbar-nav > li > a:focus { + color: #333; + background-color: transparent; +} +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:hover, +.navbar-default .navbar-nav > .active > a:focus { + color: #555; + background-color: #e7e7e7; +} +.navbar-default .navbar-nav > .disabled > a, +.navbar-default .navbar-nav > .disabled > a:hover, +.navbar-default .navbar-nav > .disabled > a:focus { + color: #ccc; + background-color: transparent; +} +.navbar-default .navbar-toggle { + border-color: #ddd; +} +.navbar-default .navbar-toggle:hover, +.navbar-default .navbar-toggle:focus { + background-color: #ddd; +} +.navbar-default .navbar-toggle .icon-bar { + background-color: #888; +} +.navbar-default .navbar-collapse, +.navbar-default .navbar-form { + border-color: #e7e7e7; +} +.navbar-default .navbar-nav > .open > a, +.navbar-default .navbar-nav > .open > a:hover, +.navbar-default .navbar-nav > .open > a:focus { + color: #555; + background-color: #e7e7e7; +} +@media (max-width: 767px) { + .navbar-default .navbar-nav .open .dropdown-menu > li > a { + color: #777; + } + .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { + color: #333; + background-color: transparent; + } + .navbar-default .navbar-nav .open .dropdown-menu > .active > a, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #555; + background-color: #e7e7e7; + } + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #ccc; + background-color: transparent; + } +} +.navbar-default .navbar-link { + color: #777; +} +.navbar-default .navbar-link:hover { + color: #333; +} +.navbar-default .btn-link { + color: #777; +} +.navbar-default .btn-link:hover, +.navbar-default .btn-link:focus { + color: #333; +} +.navbar-default .btn-link[disabled]:hover, +fieldset[disabled] .navbar-default .btn-link:hover, +.navbar-default .btn-link[disabled]:focus, +fieldset[disabled] .navbar-default .btn-link:focus { + color: #ccc; +} +.navbar-inverse { + background-color: #222; + border-color: #080808; +} +.navbar-inverse .navbar-brand { + color: #9d9d9d; +} +.navbar-inverse .navbar-brand:hover, +.navbar-inverse .navbar-brand:focus { + color: #fff; + background-color: transparent; +} +.navbar-inverse .navbar-text { + color: #9d9d9d; +} +.navbar-inverse .navbar-nav > li > a { + color: #9d9d9d; +} +.navbar-inverse .navbar-nav > li > a:hover, +.navbar-inverse .navbar-nav > li > a:focus { + color: #fff; + background-color: transparent; +} +.navbar-inverse .navbar-nav > .active > a, +.navbar-inverse .navbar-nav > .active > a:hover, +.navbar-inverse .navbar-nav > .active > a:focus { + color: #fff; + background-color: #080808; +} +.navbar-inverse .navbar-nav > .disabled > a, +.navbar-inverse .navbar-nav > .disabled > a:hover, +.navbar-inverse .navbar-nav > .disabled > a:focus { + color: #444; + background-color: transparent; +} +.navbar-inverse .navbar-toggle { + border-color: #333; +} +.navbar-inverse .navbar-toggle:hover, +.navbar-inverse .navbar-toggle:focus { + background-color: #333; +} +.navbar-inverse .navbar-toggle .icon-bar { + background-color: #fff; +} +.navbar-inverse .navbar-collapse, +.navbar-inverse .navbar-form { + border-color: #101010; +} +.navbar-inverse .navbar-nav > .open > a, +.navbar-inverse .navbar-nav > .open > a:hover, +.navbar-inverse .navbar-nav > .open > a:focus { + color: #fff; + background-color: #080808; +} +@media (max-width: 767px) { + .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header { + border-color: #080808; + } + .navbar-inverse .navbar-nav .open .dropdown-menu .divider { + background-color: #080808; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a { + color: #9d9d9d; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { + color: #fff; + background-color: transparent; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #fff; + background-color: #080808; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #444; + background-color: transparent; + } +} +.navbar-inverse .navbar-link { + color: #9d9d9d; +} +.navbar-inverse .navbar-link:hover { + color: #fff; +} +.navbar-inverse .btn-link { + color: #9d9d9d; +} +.navbar-inverse .btn-link:hover, +.navbar-inverse .btn-link:focus { + color: #fff; +} +.navbar-inverse .btn-link[disabled]:hover, +fieldset[disabled] .navbar-inverse .btn-link:hover, +.navbar-inverse .btn-link[disabled]:focus, +fieldset[disabled] .navbar-inverse .btn-link:focus { + color: #444; +} +.breadcrumb { + padding: 8px 15px; + margin-bottom: 20px; + list-style: none; + background-color: #f5f5f5; + border-radius: 4px; +} +.breadcrumb > li { + display: inline-block; +} +.breadcrumb > li + li:before { + padding: 0 5px; + color: #ccc; + content: "/\00a0"; +} +.breadcrumb > .active { + color: #777; +} +.pagination { + display: inline-block; + padding-left: 0; + margin: 20px 0; + border-radius: 4px; +} +.pagination > li { + display: inline; +} +.pagination > li > a, +.pagination > li > span { + position: relative; + float: left; + padding: 6px 12px; + margin-left: -1px; + line-height: 1.42857143; + color: #428bca; + text-decoration: none; + background-color: #fff; + border: 1px solid #ddd; +} +.pagination > li:first-child > a, +.pagination > li:first-child > span { + margin-left: 0; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; +} +.pagination > li:last-child > a, +.pagination > li:last-child > span { + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; +} +.pagination > li > a:hover, +.pagination > li > span:hover, +.pagination > li > a:focus, +.pagination > li > span:focus { + color: #2a6496; + background-color: #eee; + border-color: #ddd; +} +.pagination > .active > a, +.pagination > .active > span, +.pagination > .active > a:hover, +.pagination > .active > span:hover, +.pagination > .active > a:focus, +.pagination > .active > span:focus { + z-index: 2; + color: #fff; + cursor: default; + background-color: #428bca; + border-color: #428bca; +} +.pagination > .disabled > span, +.pagination > .disabled > span:hover, +.pagination > .disabled > span:focus, +.pagination > .disabled > a, +.pagination > .disabled > a:hover, +.pagination > .disabled > a:focus { + color: #777; + cursor: not-allowed; + background-color: #fff; + border-color: #ddd; +} +.pagination-lg > li > a, +.pagination-lg > li > span { + padding: 10px 16px; + font-size: 18px; +} +.pagination-lg > li:first-child > a, +.pagination-lg > li:first-child > span { + border-top-left-radius: 6px; + border-bottom-left-radius: 6px; +} +.pagination-lg > li:last-child > a, +.pagination-lg > li:last-child > span { + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; +} +.pagination-sm > li > a, +.pagination-sm > li > span { + padding: 5px 10px; + font-size: 12px; +} +.pagination-sm > li:first-child > a, +.pagination-sm > li:first-child > span { + border-top-left-radius: 3px; + border-bottom-left-radius: 3px; +} +.pagination-sm > li:last-child > a, +.pagination-sm > li:last-child > span { + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; +} +.pager { + padding-left: 0; + margin: 20px 0; + text-align: center; + list-style: none; +} +.pager li { + display: inline; +} +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + border-radius: 15px; +} +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: #eee; +} +.pager .next > a, +.pager .next > span { + float: right; +} +.pager .previous > a, +.pager .previous > span { + float: left; +} +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + color: #777; + cursor: not-allowed; + background-color: #fff; +} +.label { + display: inline; + padding: .2em .6em .3em; + font-size: 75%; + font-weight: bold; + line-height: 1; + color: #fff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: .25em; +} +a.label:hover, +a.label:focus { + color: #fff; + text-decoration: none; + cursor: pointer; +} +.label:empty { + display: none; +} +.btn .label { + position: relative; + top: -1px; +} +.label-default { + background-color: #777; +} +.label-default[href]:hover, +.label-default[href]:focus { + background-color: #5e5e5e; +} +.label-primary { + background-color: #428bca; +} +.label-primary[href]:hover, +.label-primary[href]:focus { + background-color: #3071a9; +} +.label-success { + background-color: #5cb85c; +} +.label-success[href]:hover, +.label-success[href]:focus { + background-color: #449d44; +} +.label-info { + background-color: #5bc0de; +} +.label-info[href]:hover, +.label-info[href]:focus { + background-color: #31b0d5; +} +.label-warning { + background-color: #f0ad4e; +} +.label-warning[href]:hover, +.label-warning[href]:focus { + background-color: #ec971f; +} +.label-danger { + background-color: #d9534f; +} +.label-danger[href]:hover, +.label-danger[href]:focus { + background-color: #c9302c; +} +.badge { + display: inline-block; + min-width: 10px; + padding: 3px 7px; + font-size: 12px; + font-weight: bold; + line-height: 1; + color: #fff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + background-color: #777; + border-radius: 10px; +} +.badge:empty { + display: none; +} +.btn .badge { + position: relative; + top: -1px; +} +.btn-xs .badge { + top: 0; + padding: 1px 5px; +} +a.badge:hover, +a.badge:focus { + color: #fff; + text-decoration: none; + cursor: pointer; +} +a.list-group-item.active > .badge, +.nav-pills > .active > a > .badge { + color: #428bca; + background-color: #fff; +} +.nav-pills > li > a > .badge { + margin-left: 3px; +} +.jumbotron { + padding: 30px 15px; + margin-bottom: 30px; + color: inherit; + background-color: #eee; +} +.jumbotron h1, +.jumbotron .h1 { + color: inherit; +} +.jumbotron p { + margin-bottom: 15px; + font-size: 21px; + font-weight: 200; +} +.jumbotron > hr { + border-top-color: #d5d5d5; +} +.container .jumbotron, +.container-fluid .jumbotron { + border-radius: 6px; +} +.jumbotron .container { + max-width: 100%; +} +@media screen and (min-width: 768px) { + .jumbotron { + padding: 48px 0; + } + .container .jumbotron { + padding-right: 60px; + padding-left: 60px; + } + .jumbotron h1, + .jumbotron .h1 { + font-size: 63px; + } +} +.thumbnail { + display: block; + padding: 4px; + margin-bottom: 20px; + line-height: 1.42857143; + background-color: #fff; + border: 1px solid #ddd; + border-radius: 4px; + -webkit-transition: border .2s ease-in-out; + -o-transition: border .2s ease-in-out; + transition: border .2s ease-in-out; +} +.thumbnail > img, +.thumbnail a > img { + margin-right: auto; + margin-left: auto; +} +a.thumbnail:hover, +a.thumbnail:focus, +a.thumbnail.active { + border-color: #428bca; +} +.thumbnail .caption { + padding: 9px; + color: #333; +} +.alert { + padding: 15px; + margin-bottom: 20px; + border: 1px solid transparent; + border-radius: 4px; +} +.alert h4 { + margin-top: 0; + color: inherit; +} +.alert .alert-link { + font-weight: bold; +} +.alert > p, +.alert > ul { + margin-bottom: 0; +} +.alert > p + p { + margin-top: 5px; +} +.alert-dismissable, +.alert-dismissible { + padding-right: 35px; +} +.alert-dismissable .close, +.alert-dismissible .close { + position: relative; + top: -2px; + right: -21px; + color: inherit; +} +.alert-success { + color: #3c763d; + background-color: #dff0d8; + border-color: #d6e9c6; +} +.alert-success hr { + border-top-color: #c9e2b3; +} +.alert-success .alert-link { + color: #2b542c; +} +.alert-info { + color: #31708f; + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-info hr { + border-top-color: #a6e1ec; +} +.alert-info .alert-link { + color: #245269; +} +.alert-warning { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #faebcc; +} +.alert-warning hr { + border-top-color: #f7e1b5; +} +.alert-warning .alert-link { + color: #66512c; +} +.alert-danger { + color: #a94442; + background-color: #f2dede; + border-color: #ebccd1; +} +.alert-danger hr { + border-top-color: #e4b9c0; +} +.alert-danger .alert-link { + color: #843534; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +@-o-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +.progress { + height: 20px; + margin-bottom: 20px; + overflow: hidden; + background-color: #f5f5f5; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1); +} +.progress-bar { + float: left; + width: 0; + height: 100%; + font-size: 12px; + line-height: 20px; + color: #fff; + text-align: center; + background-color: #428bca; + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15); + -webkit-transition: width .6s ease; + -o-transition: width .6s ease; + transition: width .6s ease; +} +.progress-striped .progress-bar, +.progress-bar-striped { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + background-size: 40px 40px; +} +.progress.active .progress-bar, +.progress-bar.active { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-bar-success { + background-color: #5cb85c; +} +.progress-striped .progress-bar-success { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); +} +.progress-bar-info { + background-color: #5bc0de; +} +.progress-striped .progress-bar-info { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); +} +.progress-bar-warning { + background-color: #f0ad4e; +} +.progress-striped .progress-bar-warning { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); +} +.progress-bar-danger { + background-color: #d9534f; +} +.progress-striped .progress-bar-danger { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); +} +.media { + margin-top: 15px; +} +.media:first-child { + margin-top: 0; +} +.media-right, +.media > .pull-right { + padding-left: 10px; +} +.media-left, +.media > .pull-left { + padding-right: 10px; +} +.media-left, +.media-right, +.media-body { + display: table-cell; + vertical-align: top; +} +.media-middle { + vertical-align: middle; +} +.media-bottom { + vertical-align: bottom; +} +.media-heading { + margin-top: 0; + margin-bottom: 5px; +} +.media-list { + padding-left: 0; + list-style: none; +} +.list-group { + padding-left: 0; + margin-bottom: 20px; +} +.list-group-item { + position: relative; + display: block; + padding: 10px 15px; + margin-bottom: -1px; + background-color: #fff; + border: 1px solid #ddd; +} +.list-group-item:first-child { + border-top-left-radius: 4px; + border-top-right-radius: 4px; +} +.list-group-item:last-child { + margin-bottom: 0; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; +} +.list-group-item > .badge { + float: right; +} +.list-group-item > .badge + .badge { + margin-right: 5px; +} +a.list-group-item { + color: #555; +} +a.list-group-item .list-group-item-heading { + color: #333; +} +a.list-group-item:hover, +a.list-group-item:focus { + color: #555; + text-decoration: none; + background-color: #f5f5f5; +} +.list-group-item.disabled, +.list-group-item.disabled:hover, +.list-group-item.disabled:focus { + color: #777; + cursor: not-allowed; + background-color: #eee; +} +.list-group-item.disabled .list-group-item-heading, +.list-group-item.disabled:hover .list-group-item-heading, +.list-group-item.disabled:focus .list-group-item-heading { + color: inherit; +} +.list-group-item.disabled .list-group-item-text, +.list-group-item.disabled:hover .list-group-item-text, +.list-group-item.disabled:focus .list-group-item-text { + color: #777; +} +.list-group-item.active, +.list-group-item.active:hover, +.list-group-item.active:focus { + z-index: 2; + color: #fff; + background-color: #428bca; + border-color: #428bca; +} +.list-group-item.active .list-group-item-heading, +.list-group-item.active:hover .list-group-item-heading, +.list-group-item.active:focus .list-group-item-heading, +.list-group-item.active .list-group-item-heading > small, +.list-group-item.active:hover .list-group-item-heading > small, +.list-group-item.active:focus .list-group-item-heading > small, +.list-group-item.active .list-group-item-heading > .small, +.list-group-item.active:hover .list-group-item-heading > .small, +.list-group-item.active:focus .list-group-item-heading > .small { + color: inherit; +} +.list-group-item.active .list-group-item-text, +.list-group-item.active:hover .list-group-item-text, +.list-group-item.active:focus .list-group-item-text { + color: #e1edf7; +} +.list-group-item-success { + color: #3c763d; + background-color: #dff0d8; +} +a.list-group-item-success { + color: #3c763d; +} +a.list-group-item-success .list-group-item-heading { + color: inherit; +} +a.list-group-item-success:hover, +a.list-group-item-success:focus { + color: #3c763d; + background-color: #d0e9c6; +} +a.list-group-item-success.active, +a.list-group-item-success.active:hover, +a.list-group-item-success.active:focus { + color: #fff; + background-color: #3c763d; + border-color: #3c763d; +} +.list-group-item-info { + color: #31708f; + background-color: #d9edf7; +} +a.list-group-item-info { + color: #31708f; +} +a.list-group-item-info .list-group-item-heading { + color: inherit; +} +a.list-group-item-info:hover, +a.list-group-item-info:focus { + color: #31708f; + background-color: #c4e3f3; +} +a.list-group-item-info.active, +a.list-group-item-info.active:hover, +a.list-group-item-info.active:focus { + color: #fff; + background-color: #31708f; + border-color: #31708f; +} +.list-group-item-warning { + color: #8a6d3b; + background-color: #fcf8e3; +} +a.list-group-item-warning { + color: #8a6d3b; +} +a.list-group-item-warning .list-group-item-heading { + color: inherit; +} +a.list-group-item-warning:hover, +a.list-group-item-warning:focus { + color: #8a6d3b; + background-color: #faf2cc; +} +a.list-group-item-warning.active, +a.list-group-item-warning.active:hover, +a.list-group-item-warning.active:focus { + color: #fff; + background-color: #8a6d3b; + border-color: #8a6d3b; +} +.list-group-item-danger { + color: #a94442; + background-color: #f2dede; +} +a.list-group-item-danger { + color: #a94442; +} +a.list-group-item-danger .list-group-item-heading { + color: inherit; +} +a.list-group-item-danger:hover, +a.list-group-item-danger:focus { + color: #a94442; + background-color: #ebcccc; +} +a.list-group-item-danger.active, +a.list-group-item-danger.active:hover, +a.list-group-item-danger.active:focus { + color: #fff; + background-color: #a94442; + border-color: #a94442; +} +.list-group-item-heading { + margin-top: 0; + margin-bottom: 5px; +} +.list-group-item-text { + margin-bottom: 0; + line-height: 1.3; +} +.panel { + margin-bottom: 20px; + background-color: #fff; + border: 1px solid transparent; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05); + box-shadow: 0 1px 1px rgba(0, 0, 0, .05); +} +.panel-body { + padding: 15px; +} +.panel-heading { + padding: 10px 15px; + border-bottom: 1px solid transparent; + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} +.panel-heading > .dropdown .dropdown-toggle { + color: inherit; +} +.panel-title { + margin-top: 0; + margin-bottom: 0; + font-size: 16px; + color: inherit; +} +.panel-title > a { + color: inherit; +} +.panel-footer { + padding: 10px 15px; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel > .list-group, +.panel > .panel-collapse > .list-group { + margin-bottom: 0; +} +.panel > .list-group .list-group-item, +.panel > .panel-collapse > .list-group .list-group-item { + border-width: 1px 0; + border-radius: 0; +} +.panel > .list-group:first-child .list-group-item:first-child, +.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child { + border-top: 0; + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} +.panel > .list-group:last-child .list-group-item:last-child, +.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child { + border-bottom: 0; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel-heading + .list-group .list-group-item:first-child { + border-top-width: 0; +} +.list-group + .panel-footer { + border-top-width: 0; +} +.panel > .table, +.panel > .table-responsive > .table, +.panel > .panel-collapse > .table { + margin-bottom: 0; +} +.panel > .table caption, +.panel > .table-responsive > .table caption, +.panel > .panel-collapse > .table caption { + padding-right: 15px; + padding-left: 15px; +} +.panel > .table:first-child, +.panel > .table-responsive:first-child > .table:first-child { + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} +.panel > .table:first-child > thead:first-child > tr:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child { + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} +.panel > .table:first-child > thead:first-child > tr:first-child td:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child, +.panel > .table:first-child > thead:first-child > tr:first-child th:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child { + border-top-left-radius: 3px; +} +.panel > .table:first-child > thead:first-child > tr:first-child td:last-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child, +.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child, +.panel > .table:first-child > thead:first-child > tr:first-child th:last-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child, +.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child { + border-top-right-radius: 3px; +} +.panel > .table:last-child, +.panel > .table-responsive:last-child > .table:last-child { + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child { + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child, +.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child { + border-bottom-left-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child, +.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child { + border-bottom-right-radius: 3px; +} +.panel > .panel-body + .table, +.panel > .panel-body + .table-responsive, +.panel > .table + .panel-body, +.panel > .table-responsive + .panel-body { + border-top: 1px solid #ddd; +} +.panel > .table > tbody:first-child > tr:first-child th, +.panel > .table > tbody:first-child > tr:first-child td { + border-top: 0; +} +.panel > .table-bordered, +.panel > .table-responsive > .table-bordered { + border: 0; +} +.panel > .table-bordered > thead > tr > th:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:first-child, +.panel > .table-bordered > tbody > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, +.panel > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-bordered > thead > tr > td:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:first-child, +.panel > .table-bordered > tbody > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, +.panel > .table-bordered > tfoot > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; +} +.panel > .table-bordered > thead > tr > th:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:last-child, +.panel > .table-bordered > tbody > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, +.panel > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-bordered > thead > tr > td:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:last-child, +.panel > .table-bordered > tbody > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, +.panel > .table-bordered > tfoot > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; +} +.panel > .table-bordered > thead > tr:first-child > td, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > td, +.panel > .table-bordered > tbody > tr:first-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td, +.panel > .table-bordered > thead > tr:first-child > th, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > th, +.panel > .table-bordered > tbody > tr:first-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th { + border-bottom: 0; +} +.panel > .table-bordered > tbody > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, +.panel > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-bordered > tbody > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, +.panel > .table-bordered > tfoot > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th { + border-bottom: 0; +} +.panel > .table-responsive { + margin-bottom: 0; + border: 0; +} +.panel-group { + margin-bottom: 20px; +} +.panel-group .panel { + margin-bottom: 0; + border-radius: 4px; +} +.panel-group .panel + .panel { + margin-top: 5px; +} +.panel-group .panel-heading { + border-bottom: 0; +} +.panel-group .panel-heading + .panel-collapse > .panel-body, +.panel-group .panel-heading + .panel-collapse > .list-group { + border-top: 1px solid #ddd; +} +.panel-group .panel-footer { + border-top: 0; +} +.panel-group .panel-footer + .panel-collapse .panel-body { + border-bottom: 1px solid #ddd; +} +.panel-default { + border-color: #ddd; +} +.panel-default > .panel-heading { + color: #333; + background-color: #f5f5f5; + border-color: #ddd; +} +.panel-default > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #ddd; +} +.panel-default > .panel-heading .badge { + color: #f5f5f5; + background-color: #333; +} +.panel-default > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #ddd; +} +.panel-primary { + border-color: #428bca; +} +.panel-primary > .panel-heading { + color: #fff; + background-color: #428bca; + border-color: #428bca; +} +.panel-primary > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #428bca; +} +.panel-primary > .panel-heading .badge { + color: #428bca; + background-color: #fff; +} +.panel-primary > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #428bca; +} +.panel-success { + border-color: #d6e9c6; +} +.panel-success > .panel-heading { + color: #3c763d; + background-color: #dff0d8; + border-color: #d6e9c6; +} +.panel-success > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #d6e9c6; +} +.panel-success > .panel-heading .badge { + color: #dff0d8; + background-color: #3c763d; +} +.panel-success > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #d6e9c6; +} +.panel-info { + border-color: #bce8f1; +} +.panel-info > .panel-heading { + color: #31708f; + background-color: #d9edf7; + border-color: #bce8f1; +} +.panel-info > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #bce8f1; +} +.panel-info > .panel-heading .badge { + color: #d9edf7; + background-color: #31708f; +} +.panel-info > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #bce8f1; +} +.panel-warning { + border-color: #faebcc; +} +.panel-warning > .panel-heading { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #faebcc; +} +.panel-warning > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #faebcc; +} +.panel-warning > .panel-heading .badge { + color: #fcf8e3; + background-color: #8a6d3b; +} +.panel-warning > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #faebcc; +} +.panel-danger { + border-color: #ebccd1; +} +.panel-danger > .panel-heading { + color: #a94442; + background-color: #f2dede; + border-color: #ebccd1; +} +.panel-danger > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #ebccd1; +} +.panel-danger > .panel-heading .badge { + color: #f2dede; + background-color: #a94442; +} +.panel-danger > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #ebccd1; +} +.embed-responsive { + position: relative; + display: block; + height: 0; + padding: 0; + overflow: hidden; +} +.embed-responsive .embed-responsive-item, +.embed-responsive iframe, +.embed-responsive embed, +.embed-responsive object, +.embed-responsive video { + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 100%; + height: 100%; + border: 0; +} +.embed-responsive.embed-responsive-16by9 { + padding-bottom: 56.25%; +} +.embed-responsive.embed-responsive-4by3 { + padding-bottom: 75%; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #e3e3e3; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, .15); +} +.well-lg { + padding: 24px; + border-radius: 6px; +} +.well-sm { + padding: 9px; + border-radius: 3px; +} +.close { + float: right; + font-size: 21px; + font-weight: bold; + line-height: 1; + color: #000; + text-shadow: 0 1px 0 #fff; + filter: alpha(opacity=20); + opacity: .2; +} +.close:hover, +.close:focus { + color: #000; + text-decoration: none; + cursor: pointer; + filter: alpha(opacity=50); + opacity: .5; +} +button.close { + -webkit-appearance: none; + padding: 0; + cursor: pointer; + background: transparent; + border: 0; +} +.modal-open { + overflow: hidden; +} +.modal { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + display: none; + overflow: hidden; + -webkit-overflow-scrolling: touch; + outline: 0; +} +.modal.fade .modal-dialog { + -webkit-transition: -webkit-transform .3s ease-out; + -o-transition: -o-transform .3s ease-out; + transition: transform .3s ease-out; + -webkit-transform: translate(0, -25%); + -ms-transform: translate(0, -25%); + -o-transform: translate(0, -25%); + transform: translate(0, -25%); +} +.modal.in .modal-dialog { + -webkit-transform: translate(0, 0); + -ms-transform: translate(0, 0); + -o-transform: translate(0, 0); + transform: translate(0, 0); +} +.modal-open .modal { + overflow-x: hidden; + overflow-y: auto; +} +.modal-dialog { + position: relative; + width: auto; + margin: 10px; +} +.modal-content { + position: relative; + background-color: #fff; + -webkit-background-clip: padding-box; + background-clip: padding-box; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, .2); + border-radius: 6px; + outline: 0; + -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5); + box-shadow: 0 3px 9px rgba(0, 0, 0, .5); +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + background-color: #000; +} +.modal-backdrop.fade { + filter: alpha(opacity=0); + opacity: 0; +} +.modal-backdrop.in { + filter: alpha(opacity=50); + opacity: .5; +} +.modal-header { + min-height: 16.42857143px; + padding: 15px; + border-bottom: 1px solid #e5e5e5; +} +.modal-header .close { + margin-top: -2px; +} +.modal-title { + margin: 0; + line-height: 1.42857143; +} +.modal-body { + position: relative; + padding: 15px; +} +.modal-footer { + padding: 15px; + text-align: right; + border-top: 1px solid #e5e5e5; +} +.modal-footer .btn + .btn { + margin-bottom: 0; + margin-left: 5px; +} +.modal-footer .btn-group .btn + .btn { + margin-left: -1px; +} +.modal-footer .btn-block + .btn-block { + margin-left: 0; +} +.modal-scrollbar-measure { + position: absolute; + top: -9999px; + width: 50px; + height: 50px; + overflow: scroll; +} +@media (min-width: 768px) { + .modal-dialog { + width: 600px; + margin: 30px auto; + } + .modal-content { + -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5); + box-shadow: 0 5px 15px rgba(0, 0, 0, .5); + } + .modal-sm { + width: 300px; + } +} +@media (min-width: 992px) { + .modal-lg { + width: 900px; + } +} +.tooltip { + position: absolute; + z-index: 1070; + display: block; + font-size: 12px; + line-height: 1.4; + visibility: visible; + filter: alpha(opacity=0); + opacity: 0; +} +.tooltip.in { + filter: alpha(opacity=90); + opacity: .9; +} +.tooltip.top { + padding: 5px 0; + margin-top: -3px; +} +.tooltip.right { + padding: 0 5px; + margin-left: 3px; +} +.tooltip.bottom { + padding: 5px 0; + margin-top: 3px; +} +.tooltip.left { + padding: 0 5px; + margin-left: -3px; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #fff; + text-align: center; + text-decoration: none; + background-color: #000; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-width: 5px 5px 0; + border-top-color: #000; +} +.tooltip.top-left .tooltip-arrow { + bottom: 0; + left: 5px; + border-width: 5px 5px 0; + border-top-color: #000; +} +.tooltip.top-right .tooltip-arrow { + right: 5px; + bottom: 0; + border-width: 5px 5px 0; + border-top-color: #000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-width: 5px 5px 5px 0; + border-right-color: #000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-width: 5px 0 5px 5px; + border-left-color: #000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-width: 0 5px 5px; + border-bottom-color: #000; +} +.tooltip.bottom-left .tooltip-arrow { + top: 0; + left: 5px; + border-width: 0 5px 5px; + border-bottom-color: #000; +} +.tooltip.bottom-right .tooltip-arrow { + top: 0; + right: 5px; + border-width: 0 5px 5px; + border-bottom-color: #000; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1060; + display: none; + max-width: 276px; + padding: 1px; + font-size: 14px; + font-weight: normal; + line-height: 1.42857143; + text-align: left; + white-space: normal; + background-color: #fff; + -webkit-background-clip: padding-box; + background-clip: padding-box; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, .2); + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2); + box-shadow: 0 5px 10px rgba(0, 0, 0, .2); +} +.popover.top { + margin-top: -10px; +} +.popover.right { + margin-left: 10px; +} +.popover.bottom { + margin-top: 10px; +} +.popover.left { + margin-left: -10px; +} +.popover-title { + padding: 8px 14px; + margin: 0; + font-size: 14px; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + border-radius: 5px 5px 0 0; +} +.popover-content { + padding: 9px 14px; +} +.popover > .arrow, +.popover > .arrow:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.popover > .arrow { + border-width: 11px; +} +.popover > .arrow:after { + content: ""; + border-width: 10px; +} +.popover.top > .arrow { + bottom: -11px; + left: 50%; + margin-left: -11px; + border-top-color: #999; + border-top-color: rgba(0, 0, 0, .25); + border-bottom-width: 0; +} +.popover.top > .arrow:after { + bottom: 1px; + margin-left: -10px; + content: " "; + border-top-color: #fff; + border-bottom-width: 0; +} +.popover.right > .arrow { + top: 50%; + left: -11px; + margin-top: -11px; + border-right-color: #999; + border-right-color: rgba(0, 0, 0, .25); + border-left-width: 0; +} +.popover.right > .arrow:after { + bottom: -10px; + left: 1px; + content: " "; + border-right-color: #fff; + border-left-width: 0; +} +.popover.bottom > .arrow { + top: -11px; + left: 50%; + margin-left: -11px; + border-top-width: 0; + border-bottom-color: #999; + border-bottom-color: rgba(0, 0, 0, .25); +} +.popover.bottom > .arrow:after { + top: 1px; + margin-left: -10px; + content: " "; + border-top-width: 0; + border-bottom-color: #fff; +} +.popover.left > .arrow { + top: 50%; + right: -11px; + margin-top: -11px; + border-right-width: 0; + border-left-color: #999; + border-left-color: rgba(0, 0, 0, .25); +} +.popover.left > .arrow:after { + right: 1px; + bottom: -10px; + content: " "; + border-right-width: 0; + border-left-color: #fff; +} +.carousel { + position: relative; +} +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} +.carousel-inner > .item { + position: relative; + display: none; + -webkit-transition: .6s ease-in-out left; + -o-transition: .6s ease-in-out left; + transition: .6s ease-in-out left; +} +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + line-height: 1; +} +@media all and (transform-3d), (-webkit-transform-3d) { + .carousel-inner > .item { + -webkit-transition: -webkit-transform .6s ease-in-out; + -o-transition: -o-transform .6s ease-in-out; + transition: transform .6s ease-in-out; + + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + -webkit-perspective: 1000; + perspective: 1000; + } + .carousel-inner > .item.next, + .carousel-inner > .item.active.right { + left: 0; + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + } + .carousel-inner > .item.prev, + .carousel-inner > .item.active.left { + left: 0; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + } + .carousel-inner > .item.next.left, + .carousel-inner > .item.prev.right, + .carousel-inner > .item.active { + left: 0; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} +.carousel-inner > .active, +.carousel-inner > .next, +.carousel-inner > .prev { + display: block; +} +.carousel-inner > .active { + left: 0; +} +.carousel-inner > .next, +.carousel-inner > .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel-inner > .next { + left: 100%; +} +.carousel-inner > .prev { + left: -100%; +} +.carousel-inner > .next.left, +.carousel-inner > .prev.right { + left: 0; +} +.carousel-inner > .active.left { + left: -100%; +} +.carousel-inner > .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 15%; + font-size: 20px; + color: #fff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, .6); + filter: alpha(opacity=50); + opacity: .5; +} +.carousel-control.left { + background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%); + background-image: -o-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%); + background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .5)), to(rgba(0, 0, 0, .0001))); + background-image: linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); + background-repeat: repeat-x; +} +.carousel-control.right { + right: 0; + left: auto; + background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%); + background-image: -o-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%); + background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .0001)), to(rgba(0, 0, 0, .5))); + background-image: linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); + background-repeat: repeat-x; +} +.carousel-control:hover, +.carousel-control:focus { + color: #fff; + text-decoration: none; + filter: alpha(opacity=90); + outline: 0; + opacity: .9; +} +.carousel-control .icon-prev, +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-left, +.carousel-control .glyphicon-chevron-right { + position: absolute; + top: 50%; + z-index: 5; + display: inline-block; +} +.carousel-control .icon-prev, +.carousel-control .glyphicon-chevron-left { + left: 50%; + margin-left: -10px; +} +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-right { + right: 50%; + margin-right: -10px; +} +.carousel-control .icon-prev, +.carousel-control .icon-next { + width: 20px; + height: 20px; + margin-top: -10px; + font-family: serif; +} +.carousel-control .icon-prev:before { + content: '\2039'; +} +.carousel-control .icon-next:before { + content: '\203a'; +} +.carousel-indicators { + position: absolute; + bottom: 10px; + left: 50%; + z-index: 15; + width: 60%; + padding-left: 0; + margin-left: -30%; + text-align: center; + list-style: none; +} +.carousel-indicators li { + display: inline-block; + width: 10px; + height: 10px; + margin: 1px; + text-indent: -999px; + cursor: pointer; + background-color: #000 \9; + background-color: rgba(0, 0, 0, 0); + border: 1px solid #fff; + border-radius: 10px; +} +.carousel-indicators .active { + width: 12px; + height: 12px; + margin: 0; + background-color: #fff; +} +.carousel-caption { + position: absolute; + right: 15%; + bottom: 20px; + left: 15%; + z-index: 10; + padding-top: 20px; + padding-bottom: 20px; + color: #fff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, .6); +} +.carousel-caption .btn { + text-shadow: none; +} +@media screen and (min-width: 768px) { + .carousel-control .glyphicon-chevron-left, + .carousel-control .glyphicon-chevron-right, + .carousel-control .icon-prev, + .carousel-control .icon-next { + width: 30px; + height: 30px; + margin-top: -15px; + font-size: 30px; + } + .carousel-control .glyphicon-chevron-left, + .carousel-control .icon-prev { + margin-left: -15px; + } + .carousel-control .glyphicon-chevron-right, + .carousel-control .icon-next { + margin-right: -15px; + } + .carousel-caption { + right: 20%; + left: 20%; + padding-bottom: 30px; + } + .carousel-indicators { + bottom: 20px; + } +} +.clearfix:before, +.clearfix:after, +.dl-horizontal dd:before, +.dl-horizontal dd:after, +.container:before, +.container:after, +.container-fluid:before, +.container-fluid:after, +.row:before, +.row:after, +.form-horizontal .form-group:before, +.form-horizontal .form-group:after, +.btn-toolbar:before, +.btn-toolbar:after, +.btn-group-vertical > .btn-group:before, +.btn-group-vertical > .btn-group:after, +.nav:before, +.nav:after, +.navbar:before, +.navbar:after, +.navbar-header:before, +.navbar-header:after, +.navbar-collapse:before, +.navbar-collapse:after, +.pager:before, +.pager:after, +.panel-body:before, +.panel-body:after, +.modal-footer:before, +.modal-footer:after { + display: table; + content: " "; +} +.clearfix:after, +.dl-horizontal dd:after, +.container:after, +.container-fluid:after, +.row:after, +.form-horizontal .form-group:after, +.btn-toolbar:after, +.btn-group-vertical > .btn-group:after, +.nav:after, +.navbar:after, +.navbar-header:after, +.navbar-collapse:after, +.pager:after, +.panel-body:after, +.modal-footer:after { + clear: both; +} +.center-block { + display: block; + margin-right: auto; + margin-left: auto; +} +.pull-right { + float: right !important; +} +.pull-left { + float: left !important; +} +.hide { + display: none !important; +} +.show { + display: block !important; +} +.invisible { + visibility: hidden; +} +.text-hide { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} +.hidden { + display: none !important; + visibility: hidden !important; +} +.affix { + position: fixed; +} +@-ms-viewport { + width: device-width; +} +.visible-xs, +.visible-sm, +.visible-md, +.visible-lg { + display: none !important; +} +.visible-xs-block, +.visible-xs-inline, +.visible-xs-inline-block, +.visible-sm-block, +.visible-sm-inline, +.visible-sm-inline-block, +.visible-md-block, +.visible-md-inline, +.visible-md-inline-block, +.visible-lg-block, +.visible-lg-inline, +.visible-lg-inline-block { + display: none !important; +} +@media (max-width: 767px) { + .visible-xs { + display: block !important; + } + table.visible-xs { + display: table; + } + tr.visible-xs { + display: table-row !important; + } + th.visible-xs, + td.visible-xs { + display: table-cell !important; + } +} +@media (max-width: 767px) { + .visible-xs-block { + display: block !important; + } +} +@media (max-width: 767px) { + .visible-xs-inline { + display: inline !important; + } +} +@media (max-width: 767px) { + .visible-xs-inline-block { + display: inline-block !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm { + display: block !important; + } + table.visible-sm { + display: table; + } + tr.visible-sm { + display: table-row !important; + } + th.visible-sm, + td.visible-sm { + display: table-cell !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm-block { + display: block !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm-inline { + display: inline !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm-inline-block { + display: inline-block !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md { + display: block !important; + } + table.visible-md { + display: table; + } + tr.visible-md { + display: table-row !important; + } + th.visible-md, + td.visible-md { + display: table-cell !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md-block { + display: block !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md-inline { + display: inline !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md-inline-block { + display: inline-block !important; + } +} +@media (min-width: 1200px) { + .visible-lg { + display: block !important; + } + table.visible-lg { + display: table; + } + tr.visible-lg { + display: table-row !important; + } + th.visible-lg, + td.visible-lg { + display: table-cell !important; + } +} +@media (min-width: 1200px) { + .visible-lg-block { + display: block !important; + } +} +@media (min-width: 1200px) { + .visible-lg-inline { + display: inline !important; + } +} +@media (min-width: 1200px) { + .visible-lg-inline-block { + display: inline-block !important; + } +} +@media (max-width: 767px) { + .hidden-xs { + display: none !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .hidden-sm { + display: none !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-md { + display: none !important; + } +} +@media (min-width: 1200px) { + .hidden-lg { + display: none !important; + } +} +.visible-print { + display: none !important; +} +@media print { + .visible-print { + display: block !important; + } + table.visible-print { + display: table; + } + tr.visible-print { + display: table-row !important; + } + th.visible-print, + td.visible-print { + display: table-cell !important; + } +} +.visible-print-block { + display: none !important; +} +@media print { + .visible-print-block { + display: block !important; + } +} +.visible-print-inline { + display: none !important; +} +@media print { + .visible-print-inline { + display: inline !important; + } +} +.visible-print-inline-block { + display: none !important; +} +@media print { + .visible-print-inline-block { + display: inline-block !important; + } +} +@media print { + .hidden-print { + display: none !important; + } +} +/*# sourceMappingURL=bootstrap.css.map */ diff --git a/bower_components/bootstrap/dist/css/bootstrap.css.map b/bower_components/bootstrap/dist/css/bootstrap.css.map new file mode 100644 index 0000000..fa5546b --- /dev/null +++ b/bower_components/bootstrap/dist/css/bootstrap.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["bootstrap.css","less/normalize.less","less/print.less","less/glyphicons.less","less/scaffolding.less","less/mixins/vendor-prefixes.less","less/mixins/tab-focus.less","less/mixins/image.less","less/type.less","less/mixins/text-emphasis.less","less/mixins/background-variant.less","less/mixins/text-overflow.less","less/code.less","less/grid.less","less/mixins/grid.less","less/mixins/grid-framework.less","less/tables.less","less/mixins/table-row.less","less/forms.less","less/mixins/forms.less","less/buttons.less","less/mixins/buttons.less","less/mixins/opacity.less","less/component-animations.less","less/dropdowns.less","less/mixins/nav-divider.less","less/mixins/reset-filter.less","less/button-groups.less","less/mixins/border-radius.less","less/input-groups.less","less/navs.less","less/navbar.less","less/mixins/nav-vertical-align.less","less/utilities.less","less/breadcrumbs.less","less/pagination.less","less/mixins/pagination.less","less/pager.less","less/labels.less","less/mixins/labels.less","less/badges.less","less/jumbotron.less","less/thumbnails.less","less/alerts.less","less/mixins/alerts.less","less/progress-bars.less","less/mixins/gradients.less","less/mixins/progress-bar.less","less/media.less","less/list-group.less","less/mixins/list-group.less","less/panels.less","less/mixins/panels.less","less/responsive-embed.less","less/wells.less","less/close.less","less/modals.less","less/tooltip.less","less/popovers.less","less/carousel.less","less/mixins/clearfix.less","less/mixins/center-block.less","less/mixins/hide-text.less","less/responsive-utilities.less","less/mixins/responsive-visibility.less"],"names":[],"mappings":"AAAA,6DAA4D;ACQ5D;EACE,yBAAA;EACA,4BAAA;EACA,gCAAA;EDND;ACaD;EACE,WAAA;EDXD;ACwBD;;;;;;;;;;;;;EAaE,gBAAA;EDtBD;AC8BD;;;;EAIE,uBAAA;EACA,0BAAA;ED5BD;ACoCD;EACE,eAAA;EACA,WAAA;EDlCD;AC0CD;;EAEE,eAAA;EDxCD;ACkDD;EACE,+BAAA;EDhDD;ACuDD;;EAEE,YAAA;EDrDD;AC+DD;EACE,2BAAA;ED7DD;ACoED;;EAEE,mBAAA;EDlED;ACyED;EACE,oBAAA;EDvED;AC+ED;EACE,gBAAA;EACA,kBAAA;ED7ED;ACoFD;EACE,kBAAA;EACA,aAAA;EDlFD;ACyFD;EACE,gBAAA;EDvFD;AC8FD;;EAEE,gBAAA;EACA,gBAAA;EACA,oBAAA;EACA,0BAAA;ED5FD;AC+FD;EACE,aAAA;ED7FD;ACgGD;EACE,iBAAA;ED9FD;ACwGD;EACE,WAAA;EDtGD;AC6GD;EACE,kBAAA;ED3GD;ACqHD;EACE,kBAAA;EDnHD;AC0HD;EACE,8BAAA;EACA,iCAAA;UAAA,yBAAA;EACA,WAAA;EDxHD;AC+HD;EACE,gBAAA;ED7HD;ACoID;;;;EAIE,mCAAA;EACA,gBAAA;EDlID;ACoJD;;;;;EAKE,gBAAA;EACA,eAAA;EACA,WAAA;EDlJD;ACyJD;EACE,mBAAA;EDvJD;ACiKD;;EAEE,sBAAA;ED/JD;AC0KD;;;;EAIE,4BAAA;EACA,iBAAA;EDxKD;AC+KD;;EAEE,iBAAA;ED7KD;ACoLD;;EAEE,WAAA;EACA,YAAA;EDlLD;AC0LD;EACE,qBAAA;EDxLD;ACmMD;;EAEE,gCAAA;KAAA,6BAAA;UAAA,wBAAA;EACA,YAAA;EDjMD;AC0MD;;EAEE,cAAA;EDxMD;ACiND;EACE,+BAAA;EACA,8BAAA;EACA,iCAAA;EACA,yBAAA;ED/MD;ACwND;;EAEE,0BAAA;EDtND;AC6ND;EACE,2BAAA;EACA,eAAA;EACA,gCAAA;ED3ND;ACmOD;EACE,WAAA;EACA,YAAA;EDjOD;ACwOD;EACE,gBAAA;EDtOD;AC8OD;EACE,mBAAA;ED5OD;ACsPD;EACE,2BAAA;EACA,mBAAA;EDpPD;ACuPD;;EAEE,YAAA;EDrPD;AACD,sFAAqF;AE1ErF;EAnGI;;;IAGI,oCAAA;IACA,wBAAA;IACA,qCAAA;YAAA,6BAAA;IACA,8BAAA;IFgLL;EE7KC;;IAEI,4BAAA;IF+KL;EE5KC;IACI,8BAAA;IF8KL;EE3KC;IACI,+BAAA;IF6KL;EExKC;;IAEI,aAAA;IF0KL;EEvKC;;IAEI,wBAAA;IACA,0BAAA;IFyKL;EEtKC;IACI,6BAAA;IFwKL;EErKC;;IAEI,0BAAA;IFuKL;EEpKC;IACI,4BAAA;IFsKL;EEnKC;;;IAGI,YAAA;IACA,WAAA;IFqKL;EElKC;;IAEI,yBAAA;IFoKL;EE7JC;IACI,6BAAA;IF+JL;EE3JC;IACI,eAAA;IF6JL;EE3JC;;IAGQ,mCAAA;IF4JT;EEzJC;IACI,wBAAA;IF2JL;EExJC;IACI,sCAAA;IF0JL;EE3JC;;IAKQ,mCAAA;IF0JT;EEvJC;;IAGQ,mCAAA;IFwJT;EACF;AGpPD;EACE,qCAAA;EACA,uDAAA;EACA,6TAAA;EHsPD;AG/OD;EACE,oBAAA;EACA,UAAA;EACA,uBAAA;EACA,qCAAA;EACA,oBAAA;EACA,qBAAA;EACA,gBAAA;EACA,qCAAA;EACA,oCAAA;EHiPD;AG7OmC;EAAW,gBAAA;EHgP9C;AG/OmC;EAAW,gBAAA;EHkP9C;AGhPmC;;EAAW,kBAAA;EHoP9C;AGnPmC;EAAW,kBAAA;EHsP9C;AGrPmC;EAAW,kBAAA;EHwP9C;AGvPmC;EAAW,kBAAA;EH0P9C;AGzPmC;EAAW,kBAAA;EH4P9C;AG3PmC;EAAW,kBAAA;EH8P9C;AG7PmC;EAAW,kBAAA;EHgQ9C;AG/PmC;EAAW,kBAAA;EHkQ9C;AGjQmC;EAAW,kBAAA;EHoQ9C;AGnQmC;EAAW,kBAAA;EHsQ9C;AGrQmC;EAAW,kBAAA;EHwQ9C;AGvQmC;EAAW,kBAAA;EH0Q9C;AGzQmC;EAAW,kBAAA;EH4Q9C;AG3QmC;EAAW,kBAAA;EH8Q9C;AG7QmC;EAAW,kBAAA;EHgR9C;AG/QmC;EAAW,kBAAA;EHkR9C;AGjRmC;EAAW,kBAAA;EHoR9C;AGnRmC;EAAW,kBAAA;EHsR9C;AGrRmC;EAAW,kBAAA;EHwR9C;AGvRmC;EAAW,kBAAA;EH0R9C;AGzRmC;EAAW,kBAAA;EH4R9C;AG3RmC;EAAW,kBAAA;EH8R9C;AG7RmC;EAAW,kBAAA;EHgS9C;AG/RmC;EAAW,kBAAA;EHkS9C;AGjSmC;EAAW,kBAAA;EHoS9C;AGnSmC;EAAW,kBAAA;EHsS9C;AGrSmC;EAAW,kBAAA;EHwS9C;AGvSmC;EAAW,kBAAA;EH0S9C;AGzSmC;EAAW,kBAAA;EH4S9C;AG3SmC;EAAW,kBAAA;EH8S9C;AG7SmC;EAAW,kBAAA;EHgT9C;AG/SmC;EAAW,kBAAA;EHkT9C;AGjTmC;EAAW,kBAAA;EHoT9C;AGnTmC;EAAW,kBAAA;EHsT9C;AGrTmC;EAAW,kBAAA;EHwT9C;AGvTmC;EAAW,kBAAA;EH0T9C;AGzTmC;EAAW,kBAAA;EH4T9C;AG3TmC;EAAW,kBAAA;EH8T9C;AG7TmC;EAAW,kBAAA;EHgU9C;AG/TmC;EAAW,kBAAA;EHkU9C;AGjUmC;EAAW,kBAAA;EHoU9C;AGnUmC;EAAW,kBAAA;EHsU9C;AGrUmC;EAAW,kBAAA;EHwU9C;AGvUmC;EAAW,kBAAA;EH0U9C;AGzUmC;EAAW,kBAAA;EH4U9C;AG3UmC;EAAW,kBAAA;EH8U9C;AG7UmC;EAAW,kBAAA;EHgV9C;AG/UmC;EAAW,kBAAA;EHkV9C;AGjVmC;EAAW,kBAAA;EHoV9C;AGnVmC;EAAW,kBAAA;EHsV9C;AGrVmC;EAAW,kBAAA;EHwV9C;AGvVmC;EAAW,kBAAA;EH0V9C;AGzVmC;EAAW,kBAAA;EH4V9C;AG3VmC;EAAW,kBAAA;EH8V9C;AG7VmC;EAAW,kBAAA;EHgW9C;AG/VmC;EAAW,kBAAA;EHkW9C;AGjWmC;EAAW,kBAAA;EHoW9C;AGnWmC;EAAW,kBAAA;EHsW9C;AGrWmC;EAAW,kBAAA;EHwW9C;AGvWmC;EAAW,kBAAA;EH0W9C;AGzWmC;EAAW,kBAAA;EH4W9C;AG3WmC;EAAW,kBAAA;EH8W9C;AG7WmC;EAAW,kBAAA;EHgX9C;AG/WmC;EAAW,kBAAA;EHkX9C;AGjXmC;EAAW,kBAAA;EHoX9C;AGnXmC;EAAW,kBAAA;EHsX9C;AGrXmC;EAAW,kBAAA;EHwX9C;AGvXmC;EAAW,kBAAA;EH0X9C;AGzXmC;EAAW,kBAAA;EH4X9C;AG3XmC;EAAW,kBAAA;EH8X9C;AG7XmC;EAAW,kBAAA;EHgY9C;AG/XmC;EAAW,kBAAA;EHkY9C;AGjYmC;EAAW,kBAAA;EHoY9C;AGnYmC;EAAW,kBAAA;EHsY9C;AGrYmC;EAAW,kBAAA;EHwY9C;AGvYmC;EAAW,kBAAA;EH0Y9C;AGzYmC;EAAW,kBAAA;EH4Y9C;AG3YmC;EAAW,kBAAA;EH8Y9C;AG7YmC;EAAW,kBAAA;EHgZ9C;AG/YmC;EAAW,kBAAA;EHkZ9C;AGjZmC;EAAW,kBAAA;EHoZ9C;AGnZmC;EAAW,kBAAA;EHsZ9C;AGrZmC;EAAW,kBAAA;EHwZ9C;AGvZmC;EAAW,kBAAA;EH0Z9C;AGzZmC;EAAW,kBAAA;EH4Z9C;AG3ZmC;EAAW,kBAAA;EH8Z9C;AG7ZmC;EAAW,kBAAA;EHga9C;AG/ZmC;EAAW,kBAAA;EHka9C;AGjamC;EAAW,kBAAA;EHoa9C;AGnamC;EAAW,kBAAA;EHsa9C;AGramC;EAAW,kBAAA;EHwa9C;AGvamC;EAAW,kBAAA;EH0a9C;AGzamC;EAAW,kBAAA;EH4a9C;AG3amC;EAAW,kBAAA;EH8a9C;AG7amC;EAAW,kBAAA;EHgb9C;AG/amC;EAAW,kBAAA;EHkb9C;AGjbmC;EAAW,kBAAA;EHob9C;AGnbmC;EAAW,kBAAA;EHsb9C;AGrbmC;EAAW,kBAAA;EHwb9C;AGvbmC;EAAW,kBAAA;EH0b9C;AGzbmC;EAAW,kBAAA;EH4b9C;AG3bmC;EAAW,kBAAA;EH8b9C;AG7bmC;EAAW,kBAAA;EHgc9C;AG/bmC;EAAW,kBAAA;EHkc9C;AGjcmC;EAAW,kBAAA;EHoc9C;AGncmC;EAAW,kBAAA;EHsc9C;AGrcmC;EAAW,kBAAA;EHwc9C;AGvcmC;EAAW,kBAAA;EH0c9C;AGzcmC;EAAW,kBAAA;EH4c9C;AG3cmC;EAAW,kBAAA;EH8c9C;AG7cmC;EAAW,kBAAA;EHgd9C;AG/cmC;EAAW,kBAAA;EHkd9C;AGjdmC;EAAW,kBAAA;EHod9C;AGndmC;EAAW,kBAAA;EHsd9C;AGrdmC;EAAW,kBAAA;EHwd9C;AGvdmC;EAAW,kBAAA;EH0d9C;AGzdmC;EAAW,kBAAA;EH4d9C;AG3dmC;EAAW,kBAAA;EH8d9C;AG7dmC;EAAW,kBAAA;EHge9C;AG/dmC;EAAW,kBAAA;EHke9C;AGjemC;EAAW,kBAAA;EHoe9C;AGnemC;EAAW,kBAAA;EHse9C;AGremC;EAAW,kBAAA;EHwe9C;AGvemC;EAAW,kBAAA;EH0e9C;AGzemC;EAAW,kBAAA;EH4e9C;AG3emC;EAAW,kBAAA;EH8e9C;AG7emC;EAAW,kBAAA;EHgf9C;AG/emC;EAAW,kBAAA;EHkf9C;AGjfmC;EAAW,kBAAA;EHof9C;AGnfmC;EAAW,kBAAA;EHsf9C;AGrfmC;EAAW,kBAAA;EHwf9C;AGvfmC;EAAW,kBAAA;EH0f9C;AGzfmC;EAAW,kBAAA;EH4f9C;AG3fmC;EAAW,kBAAA;EH8f9C;AG7fmC;EAAW,kBAAA;EHggB9C;AG/fmC;EAAW,kBAAA;EHkgB9C;AGjgBmC;EAAW,kBAAA;EHogB9C;AGngBmC;EAAW,kBAAA;EHsgB9C;AGrgBmC;EAAW,kBAAA;EHwgB9C;AGvgBmC;EAAW,kBAAA;EH0gB9C;AGzgBmC;EAAW,kBAAA;EH4gB9C;AG3gBmC;EAAW,kBAAA;EH8gB9C;AG7gBmC;EAAW,kBAAA;EHghB9C;AG/gBmC;EAAW,kBAAA;EHkhB9C;AGjhBmC;EAAW,kBAAA;EHohB9C;AGnhBmC;EAAW,kBAAA;EHshB9C;AGrhBmC;EAAW,kBAAA;EHwhB9C;AGvhBmC;EAAW,kBAAA;EH0hB9C;AGzhBmC;EAAW,kBAAA;EH4hB9C;AG3hBmC;EAAW,kBAAA;EH8hB9C;AG7hBmC;EAAW,kBAAA;EHgiB9C;AG/hBmC;EAAW,kBAAA;EHkiB9C;AGjiBmC;EAAW,kBAAA;EHoiB9C;AGniBmC;EAAW,kBAAA;EHsiB9C;AGriBmC;EAAW,kBAAA;EHwiB9C;AGviBmC;EAAW,kBAAA;EH0iB9C;AGziBmC;EAAW,kBAAA;EH4iB9C;AG3iBmC;EAAW,kBAAA;EH8iB9C;AG7iBmC;EAAW,kBAAA;EHgjB9C;AG/iBmC;EAAW,kBAAA;EHkjB9C;AGjjBmC;EAAW,kBAAA;EHojB9C;AGnjBmC;EAAW,kBAAA;EHsjB9C;AGrjBmC;EAAW,kBAAA;EHwjB9C;AGvjBmC;EAAW,kBAAA;EH0jB9C;AGzjBmC;EAAW,kBAAA;EH4jB9C;AG3jBmC;EAAW,kBAAA;EH8jB9C;AG7jBmC;EAAW,kBAAA;EHgkB9C;AG/jBmC;EAAW,kBAAA;EHkkB9C;AGjkBmC;EAAW,kBAAA;EHokB9C;AGnkBmC;EAAW,kBAAA;EHskB9C;AGrkBmC;EAAW,kBAAA;EHwkB9C;AGvkBmC;EAAW,kBAAA;EH0kB9C;AGzkBmC;EAAW,kBAAA;EH4kB9C;AG3kBmC;EAAW,kBAAA;EH8kB9C;AG7kBmC;EAAW,kBAAA;EHglB9C;AG/kBmC;EAAW,kBAAA;EHklB9C;AGjlBmC;EAAW,kBAAA;EHolB9C;AGnlBmC;EAAW,kBAAA;EHslB9C;AGrlBmC;EAAW,kBAAA;EHwlB9C;AGvlBmC;EAAW,kBAAA;EH0lB9C;AGzlBmC;EAAW,kBAAA;EH4lB9C;AG3lBmC;EAAW,kBAAA;EH8lB9C;AG7lBmC;EAAW,kBAAA;EHgmB9C;AG/lBmC;EAAW,kBAAA;EHkmB9C;AGjmBmC;EAAW,kBAAA;EHomB9C;AGnmBmC;EAAW,kBAAA;EHsmB9C;AGrmBmC;EAAW,kBAAA;EHwmB9C;AGvmBmC;EAAW,kBAAA;EH0mB9C;AGzmBmC;EAAW,kBAAA;EH4mB9C;AG3mBmC;EAAW,kBAAA;EH8mB9C;AG7mBmC;EAAW,kBAAA;EHgnB9C;AG/mBmC;EAAW,kBAAA;EHknB9C;AGjnBmC;EAAW,kBAAA;EHonB9C;AGnnBmC;EAAW,kBAAA;EHsnB9C;AGrnBmC;EAAW,kBAAA;EHwnB9C;AGvnBmC;EAAW,kBAAA;EH0nB9C;AGznBmC;EAAW,kBAAA;EH4nB9C;AG3nBmC;EAAW,kBAAA;EH8nB9C;AI71BD;ECgEE,gCAAA;EACG,6BAAA;EACK,wBAAA;ELgyBT;AI/1BD;;EC6DE,gCAAA;EACG,6BAAA;EACK,wBAAA;ELsyBT;AI71BD;EACE,iBAAA;EACA,+CAAA;EJ+1BD;AI51BD;EACE,6DAAA;EACA,iBAAA;EACA,yBAAA;EACA,gBAAA;EACA,2BAAA;EJ81BD;AI11BD;;;;EAIE,sBAAA;EACA,oBAAA;EACA,sBAAA;EJ41BD;AIt1BD;EACE,gBAAA;EACA,uBAAA;EJw1BD;AIt1BC;;EAEE,gBAAA;EACA,4BAAA;EJw1BH;AIr1BC;EErDA,sBAAA;EAEA,4CAAA;EACA,sBAAA;EN44BD;AI/0BD;EACE,WAAA;EJi1BD;AI30BD;EACE,wBAAA;EJ60BD;AIz0BD;;;;;EGvEE,gBAAA;EACA,iBAAA;EACA,cAAA;EPu5BD;AI70BD;EACE,oBAAA;EJ+0BD;AIz0BD;EACE,cAAA;EACA,yBAAA;EACA,2BAAA;EACA,2BAAA;EACA,oBAAA;EC6FA,0CAAA;EACK,qCAAA;EACG,kCAAA;EEvLR,uBAAA;EACA,iBAAA;EACA,cAAA;EPu6BD;AIz0BD;EACE,oBAAA;EJ20BD;AIr0BD;EACE,kBAAA;EACA,qBAAA;EACA,WAAA;EACA,+BAAA;EJu0BD;AI/zBD;EACE,oBAAA;EACA,YAAA;EACA,aAAA;EACA,cAAA;EACA,YAAA;EACA,kBAAA;EACA,wBAAA;EACA,WAAA;EJi0BD;AIzzBC;;EAEE,kBAAA;EACA,aAAA;EACA,cAAA;EACA,WAAA;EACA,mBAAA;EACA,YAAA;EJ2zBH;AQt8BD;;;;;;;;;;;;EAEE,sBAAA;EACA,kBAAA;EACA,kBAAA;EACA,gBAAA;ERk9BD;AQv9BD;;;;;;;;;;;;;;;;;;;;;;;;EASI,qBAAA;EACA,gBAAA;EACA,gBAAA;ERw+BH;AQp+BD;;;;;;EAGE,kBAAA;EACA,qBAAA;ERy+BD;AQ7+BD;;;;;;;;;;;;EAQI,gBAAA;ERm/BH;AQh/BD;;;;;;EAGE,kBAAA;EACA,qBAAA;ERq/BD;AQz/BD;;;;;;;;;;;;EAQI,gBAAA;ER+/BH;AQ3/BD;;EAAU,iBAAA;ER+/BT;AQ9/BD;;EAAU,iBAAA;ERkgCT;AQjgCD;;EAAU,iBAAA;ERqgCT;AQpgCD;;EAAU,iBAAA;ERwgCT;AQvgCD;;EAAU,iBAAA;ER2gCT;AQ1gCD;;EAAU,iBAAA;ER8gCT;AQxgCD;EACE,kBAAA;ER0gCD;AQvgCD;EACE,qBAAA;EACA,iBAAA;EACA,kBAAA;EACA,kBAAA;ERygCD;AQpgCD;EAAA;IAFI,iBAAA;IR0gCD;EACF;AQlgCD;;EAEE,gBAAA;ERogCD;AQjgCD;;EAEE,2BAAA;EACA,eAAA;ERmgCD;AQ//BD;EAAuB,kBAAA;ERkgCtB;AQjgCD;EAAuB,mBAAA;ERogCtB;AQngCD;EAAuB,oBAAA;ERsgCtB;AQrgCD;EAAuB,qBAAA;ERwgCtB;AQvgCD;EAAuB,qBAAA;ER0gCtB;AQvgCD;EAAuB,2BAAA;ER0gCtB;AQzgCD;EAAuB,2BAAA;ER4gCtB;AQ3gCD;EAAuB,4BAAA;ER8gCtB;AQ3gCD;EACE,gBAAA;ER6gCD;AQ3gCD;ECrGE,gBAAA;ETmnCD;ASlnCC;EACE,gBAAA;ETonCH;AQ9gCD;ECxGE,gBAAA;ETynCD;ASxnCC;EACE,gBAAA;ET0nCH;AQjhCD;EC3GE,gBAAA;ET+nCD;AS9nCC;EACE,gBAAA;ETgoCH;AQphCD;EC9GE,gBAAA;ETqoCD;ASpoCC;EACE,gBAAA;ETsoCH;AQvhCD;ECjHE,gBAAA;ET2oCD;AS1oCC;EACE,gBAAA;ET4oCH;AQthCD;EAGE,aAAA;EE3HA,2BAAA;EVkpCD;AUjpCC;EACE,2BAAA;EVmpCH;AQvhCD;EE9HE,2BAAA;EVwpCD;AUvpCC;EACE,2BAAA;EVypCH;AQ1hCD;EEjIE,2BAAA;EV8pCD;AU7pCC;EACE,2BAAA;EV+pCH;AQ7hCD;EEpIE,2BAAA;EVoqCD;AUnqCC;EACE,2BAAA;EVqqCH;AQhiCD;EEvIE,2BAAA;EV0qCD;AUzqCC;EACE,2BAAA;EV2qCH;AQ9hCD;EACE,qBAAA;EACA,qBAAA;EACA,kCAAA;ERgiCD;AQxhCD;;EAEE,eAAA;EACA,qBAAA;ER0hCD;AQ7hCD;;;;EAMI,kBAAA;ER6hCH;AQthCD;EACE,iBAAA;EACA,kBAAA;ERwhCD;AQphCD;EALE,iBAAA;EACA,kBAAA;EAMA,mBAAA;ERuhCD;AQzhCD;EAKI,uBAAA;EACA,mBAAA;EACA,oBAAA;ERuhCH;AQlhCD;EACE,eAAA;EACA,qBAAA;ERohCD;AQlhCD;;EAEE,yBAAA;ERohCD;AQlhCD;EACE,mBAAA;ERohCD;AQlhCD;EACE,gBAAA;ERohCD;AQ3/BD;EAAA;IAVM,aAAA;IACA,cAAA;IACA,aAAA;IACA,mBAAA;IGtNJ,kBAAA;IACA,yBAAA;IACA,qBAAA;IXguCC;EQrgCH;IAHM,oBAAA;IR2gCH;EACF;AQlgCD;;EAGE,cAAA;EACA,mCAAA;ERmgCD;AQjgCD;EACE,gBAAA;EACA,2BAAA;ERmgCD;AQ//BD;EACE,oBAAA;EACA,kBAAA;EACA,mBAAA;EACA,gCAAA;ERigCD;AQ5/BG;;;EACE,kBAAA;ERggCL;AQ1gCD;;;EAmBI,gBAAA;EACA,gBAAA;EACA,yBAAA;EACA,gBAAA;ER4/BH;AQ1/BG;;;EACE,wBAAA;ER8/BL;AQt/BD;;EAEE,qBAAA;EACA,iBAAA;EACA,iCAAA;EACA,gBAAA;EACA,mBAAA;ERw/BD;AQl/BG;;;;;;EAAW,aAAA;ER0/Bd;AQz/BG;;;;;;EACE,wBAAA;ERggCL;AQ1/BD;EACE,qBAAA;EACA,oBAAA;EACA,yBAAA;ER4/BD;AYlyCD;;;;EAIE,gEAAA;EZoyCD;AYhyCD;EACE,kBAAA;EACA,gBAAA;EACA,gBAAA;EACA,2BAAA;EACA,oBAAA;EZkyCD;AY9xCD;EACE,kBAAA;EACA,gBAAA;EACA,gBAAA;EACA,2BAAA;EACA,oBAAA;EACA,wDAAA;UAAA,gDAAA;EZgyCD;AYtyCD;EASI,YAAA;EACA,iBAAA;EACA,mBAAA;EACA,0BAAA;UAAA,kBAAA;EZgyCH;AY3xCD;EACE,gBAAA;EACA,gBAAA;EACA,kBAAA;EACA,iBAAA;EACA,yBAAA;EACA,uBAAA;EACA,uBAAA;EACA,gBAAA;EACA,2BAAA;EACA,2BAAA;EACA,oBAAA;EZ6xCD;AYxyCD;EAeI,YAAA;EACA,oBAAA;EACA,gBAAA;EACA,uBAAA;EACA,+BAAA;EACA,kBAAA;EZ4xCH;AYvxCD;EACE,mBAAA;EACA,oBAAA;EZyxCD;Aan1CD;ECHE,oBAAA;EACA,mBAAA;EACA,oBAAA;EACA,qBAAA;Edy1CD;Aan1CC;EAAA;IAFE,cAAA;Iby1CD;EACF;Aar1CC;EAAA;IAFE,cAAA;Ib21CD;EACF;Aav1CD;EAAA;IAFI,eAAA;Ib61CD;EACF;Aap1CD;ECvBE,oBAAA;EACA,mBAAA;EACA,oBAAA;EACA,qBAAA;Ed82CD;Aaj1CD;ECvBE,oBAAA;EACA,qBAAA;Ed22CD;Ae32CG;EACE,oBAAA;EAEA,iBAAA;EAEA,oBAAA;EACA,qBAAA;Ef22CL;Ae31CG;EACE,aAAA;Ef61CL;Aet1CC;EACE,aAAA;Efw1CH;Aez1CC;EACE,qBAAA;Ef21CH;Ae51CC;EACE,qBAAA;Ef81CH;Ae/1CC;EACE,YAAA;Efi2CH;Ael2CC;EACE,qBAAA;Efo2CH;Aer2CC;EACE,qBAAA;Efu2CH;Aex2CC;EACE,YAAA;Ef02CH;Ae32CC;EACE,qBAAA;Ef62CH;Ae92CC;EACE,qBAAA;Efg3CH;Aej3CC;EACE,YAAA;Efm3CH;Aep3CC;EACE,qBAAA;Efs3CH;Aev3CC;EACE,oBAAA;Efy3CH;Ae32CC;EACE,aAAA;Ef62CH;Ae92CC;EACE,qBAAA;Efg3CH;Aej3CC;EACE,qBAAA;Efm3CH;Aep3CC;EACE,YAAA;Efs3CH;Aev3CC;EACE,qBAAA;Efy3CH;Ae13CC;EACE,qBAAA;Ef43CH;Ae73CC;EACE,YAAA;Ef+3CH;Aeh4CC;EACE,qBAAA;Efk4CH;Aen4CC;EACE,qBAAA;Efq4CH;Aet4CC;EACE,YAAA;Efw4CH;Aez4CC;EACE,qBAAA;Ef24CH;Ae54CC;EACE,oBAAA;Ef84CH;Ae14CC;EACE,aAAA;Ef44CH;Ae55CC;EACE,YAAA;Ef85CH;Ae/5CC;EACE,oBAAA;Efi6CH;Ael6CC;EACE,oBAAA;Efo6CH;Aer6CC;EACE,WAAA;Efu6CH;Aex6CC;EACE,oBAAA;Ef06CH;Ae36CC;EACE,oBAAA;Ef66CH;Ae96CC;EACE,WAAA;Efg7CH;Aej7CC;EACE,oBAAA;Efm7CH;Aep7CC;EACE,oBAAA;Efs7CH;Aev7CC;EACE,WAAA;Efy7CH;Ae17CC;EACE,oBAAA;Ef47CH;Ae77CC;EACE,mBAAA;Ef+7CH;Ae37CC;EACE,YAAA;Ef67CH;Ae/6CC;EACE,mBAAA;Efi7CH;Ael7CC;EACE,2BAAA;Efo7CH;Aer7CC;EACE,2BAAA;Efu7CH;Aex7CC;EACE,kBAAA;Ef07CH;Ae37CC;EACE,2BAAA;Ef67CH;Ae97CC;EACE,2BAAA;Efg8CH;Aej8CC;EACE,kBAAA;Efm8CH;Aep8CC;EACE,2BAAA;Efs8CH;Aev8CC;EACE,2BAAA;Efy8CH;Ae18CC;EACE,kBAAA;Ef48CH;Ae78CC;EACE,2BAAA;Ef+8CH;Aeh9CC;EACE,0BAAA;Efk9CH;Aen9CC;EACE,iBAAA;Efq9CH;Aaz9CD;EE9BI;IACE,aAAA;If0/CH;Een/CD;IACE,aAAA;Ifq/CD;Eet/CD;IACE,qBAAA;Ifw/CD;Eez/CD;IACE,qBAAA;If2/CD;Ee5/CD;IACE,YAAA;If8/CD;Ee//CD;IACE,qBAAA;IfigDD;EelgDD;IACE,qBAAA;IfogDD;EergDD;IACE,YAAA;IfugDD;EexgDD;IACE,qBAAA;If0gDD;Ee3gDD;IACE,qBAAA;If6gDD;Ee9gDD;IACE,YAAA;IfghDD;EejhDD;IACE,qBAAA;IfmhDD;EephDD;IACE,oBAAA;IfshDD;EexgDD;IACE,aAAA;If0gDD;Ee3gDD;IACE,qBAAA;If6gDD;Ee9gDD;IACE,qBAAA;IfghDD;EejhDD;IACE,YAAA;IfmhDD;EephDD;IACE,qBAAA;IfshDD;EevhDD;IACE,qBAAA;IfyhDD;Ee1hDD;IACE,YAAA;If4hDD;Ee7hDD;IACE,qBAAA;If+hDD;EehiDD;IACE,qBAAA;IfkiDD;EeniDD;IACE,YAAA;IfqiDD;EetiDD;IACE,qBAAA;IfwiDD;EeziDD;IACE,oBAAA;If2iDD;EeviDD;IACE,aAAA;IfyiDD;EezjDD;IACE,YAAA;If2jDD;Ee5jDD;IACE,oBAAA;If8jDD;Ee/jDD;IACE,oBAAA;IfikDD;EelkDD;IACE,WAAA;IfokDD;EerkDD;IACE,oBAAA;IfukDD;EexkDD;IACE,oBAAA;If0kDD;Ee3kDD;IACE,WAAA;If6kDD;Ee9kDD;IACE,oBAAA;IfglDD;EejlDD;IACE,oBAAA;IfmlDD;EeplDD;IACE,WAAA;IfslDD;EevlDD;IACE,oBAAA;IfylDD;Ee1lDD;IACE,mBAAA;If4lDD;EexlDD;IACE,YAAA;If0lDD;Ee5kDD;IACE,mBAAA;If8kDD;Ee/kDD;IACE,2BAAA;IfilDD;EellDD;IACE,2BAAA;IfolDD;EerlDD;IACE,kBAAA;IfulDD;EexlDD;IACE,2BAAA;If0lDD;Ee3lDD;IACE,2BAAA;If6lDD;Ee9lDD;IACE,kBAAA;IfgmDD;EejmDD;IACE,2BAAA;IfmmDD;EepmDD;IACE,2BAAA;IfsmDD;EevmDD;IACE,kBAAA;IfymDD;Ee1mDD;IACE,2BAAA;If4mDD;Ee7mDD;IACE,0BAAA;If+mDD;EehnDD;IACE,iBAAA;IfknDD;EACF;Aa9mDD;EEvCI;IACE,aAAA;IfwpDH;EejpDD;IACE,aAAA;IfmpDD;EeppDD;IACE,qBAAA;IfspDD;EevpDD;IACE,qBAAA;IfypDD;Ee1pDD;IACE,YAAA;If4pDD;Ee7pDD;IACE,qBAAA;If+pDD;EehqDD;IACE,qBAAA;IfkqDD;EenqDD;IACE,YAAA;IfqqDD;EetqDD;IACE,qBAAA;IfwqDD;EezqDD;IACE,qBAAA;If2qDD;Ee5qDD;IACE,YAAA;If8qDD;Ee/qDD;IACE,qBAAA;IfirDD;EelrDD;IACE,oBAAA;IforDD;EetqDD;IACE,aAAA;IfwqDD;EezqDD;IACE,qBAAA;If2qDD;Ee5qDD;IACE,qBAAA;If8qDD;Ee/qDD;IACE,YAAA;IfirDD;EelrDD;IACE,qBAAA;IforDD;EerrDD;IACE,qBAAA;IfurDD;EexrDD;IACE,YAAA;If0rDD;Ee3rDD;IACE,qBAAA;If6rDD;Ee9rDD;IACE,qBAAA;IfgsDD;EejsDD;IACE,YAAA;IfmsDD;EepsDD;IACE,qBAAA;IfssDD;EevsDD;IACE,oBAAA;IfysDD;EersDD;IACE,aAAA;IfusDD;EevtDD;IACE,YAAA;IfytDD;Ee1tDD;IACE,oBAAA;If4tDD;Ee7tDD;IACE,oBAAA;If+tDD;EehuDD;IACE,WAAA;IfkuDD;EenuDD;IACE,oBAAA;IfquDD;EetuDD;IACE,oBAAA;IfwuDD;EezuDD;IACE,WAAA;If2uDD;Ee5uDD;IACE,oBAAA;If8uDD;Ee/uDD;IACE,oBAAA;IfivDD;EelvDD;IACE,WAAA;IfovDD;EervDD;IACE,oBAAA;IfuvDD;EexvDD;IACE,mBAAA;If0vDD;EetvDD;IACE,YAAA;IfwvDD;Ee1uDD;IACE,mBAAA;If4uDD;Ee7uDD;IACE,2BAAA;If+uDD;EehvDD;IACE,2BAAA;IfkvDD;EenvDD;IACE,kBAAA;IfqvDD;EetvDD;IACE,2BAAA;IfwvDD;EezvDD;IACE,2BAAA;If2vDD;Ee5vDD;IACE,kBAAA;If8vDD;Ee/vDD;IACE,2BAAA;IfiwDD;EelwDD;IACE,2BAAA;IfowDD;EerwDD;IACE,kBAAA;IfuwDD;EexwDD;IACE,2BAAA;If0wDD;Ee3wDD;IACE,0BAAA;If6wDD;Ee9wDD;IACE,iBAAA;IfgxDD;EACF;AarwDD;EE9CI;IACE,aAAA;IfszDH;Ee/yDD;IACE,aAAA;IfizDD;EelzDD;IACE,qBAAA;IfozDD;EerzDD;IACE,qBAAA;IfuzDD;EexzDD;IACE,YAAA;If0zDD;Ee3zDD;IACE,qBAAA;If6zDD;Ee9zDD;IACE,qBAAA;Ifg0DD;Eej0DD;IACE,YAAA;Ifm0DD;Eep0DD;IACE,qBAAA;Ifs0DD;Eev0DD;IACE,qBAAA;Ify0DD;Ee10DD;IACE,YAAA;If40DD;Ee70DD;IACE,qBAAA;If+0DD;Eeh1DD;IACE,oBAAA;Ifk1DD;Eep0DD;IACE,aAAA;Ifs0DD;Eev0DD;IACE,qBAAA;Ify0DD;Ee10DD;IACE,qBAAA;If40DD;Ee70DD;IACE,YAAA;If+0DD;Eeh1DD;IACE,qBAAA;Ifk1DD;Een1DD;IACE,qBAAA;Ifq1DD;Eet1DD;IACE,YAAA;Ifw1DD;Eez1DD;IACE,qBAAA;If21DD;Ee51DD;IACE,qBAAA;If81DD;Ee/1DD;IACE,YAAA;Ifi2DD;Eel2DD;IACE,qBAAA;Ifo2DD;Eer2DD;IACE,oBAAA;Ifu2DD;Een2DD;IACE,aAAA;Ifq2DD;Eer3DD;IACE,YAAA;Ifu3DD;Eex3DD;IACE,oBAAA;If03DD;Ee33DD;IACE,oBAAA;If63DD;Ee93DD;IACE,WAAA;Ifg4DD;Eej4DD;IACE,oBAAA;Ifm4DD;Eep4DD;IACE,oBAAA;Ifs4DD;Eev4DD;IACE,WAAA;Ify4DD;Ee14DD;IACE,oBAAA;If44DD;Ee74DD;IACE,oBAAA;If+4DD;Eeh5DD;IACE,WAAA;Ifk5DD;Een5DD;IACE,oBAAA;Ifq5DD;Eet5DD;IACE,mBAAA;Ifw5DD;Eep5DD;IACE,YAAA;Ifs5DD;Eex4DD;IACE,mBAAA;If04DD;Ee34DD;IACE,2BAAA;If64DD;Ee94DD;IACE,2BAAA;Ifg5DD;Eej5DD;IACE,kBAAA;Ifm5DD;Eep5DD;IACE,2BAAA;Ifs5DD;Eev5DD;IACE,2BAAA;Ify5DD;Ee15DD;IACE,kBAAA;If45DD;Ee75DD;IACE,2BAAA;If+5DD;Eeh6DD;IACE,2BAAA;Ifk6DD;Een6DD;IACE,kBAAA;Ifq6DD;Eet6DD;IACE,2BAAA;Ifw6DD;Eez6DD;IACE,0BAAA;If26DD;Ee56DD;IACE,iBAAA;If86DD;EACF;AgBl/DD;EACE,+BAAA;EhBo/DD;AgBl/DD;EACE,kBAAA;EACA,qBAAA;EACA,gBAAA;EACA,kBAAA;EhBo/DD;AgBl/DD;EACE,kBAAA;EhBo/DD;AgB9+DD;EACE,aAAA;EACA,iBAAA;EACA,qBAAA;EhBg/DD;AgBn/DD;;;;;;EAWQ,cAAA;EACA,yBAAA;EACA,qBAAA;EACA,+BAAA;EhBg/DP;AgB9/DD;EAoBI,wBAAA;EACA,kCAAA;EhB6+DH;AgBlgED;;;;;;EA8BQ,eAAA;EhB4+DP;AgB1gED;EAoCI,+BAAA;EhBy+DH;AgB7gED;EAyCI,2BAAA;EhBu+DH;AgBh+DD;;;;;;EAOQ,cAAA;EhBi+DP;AgBt9DD;EACE,2BAAA;EhBw9DD;AgBz9DD;;;;;;EAQQ,2BAAA;EhBy9DP;AgBj+DD;;EAeM,0BAAA;EhBs9DL;AgB58DD;EAEI,2BAAA;EhB68DH;AgBp8DD;EAEI,2BAAA;EhBq8DH;AgB57DD;EACE,kBAAA;EACA,aAAA;EACA,uBAAA;EhB87DD;AgBz7DG;;EACE,kBAAA;EACA,aAAA;EACA,qBAAA;EhB47DL;AiBxkEC;;;;;;;;;;;;EAOI,2BAAA;EjB+kEL;AiBzkEC;;;;;EAMI,2BAAA;EjB0kEL;AiB7lEC;;;;;;;;;;;;EAOI,2BAAA;EjBomEL;AiB9lEC;;;;;EAMI,2BAAA;EjB+lEL;AiBlnEC;;;;;;;;;;;;EAOI,2BAAA;EjBynEL;AiBnnEC;;;;;EAMI,2BAAA;EjBonEL;AiBvoEC;;;;;;;;;;;;EAOI,2BAAA;EjB8oEL;AiBxoEC;;;;;EAMI,2BAAA;EjByoEL;AiB5pEC;;;;;;;;;;;;EAOI,2BAAA;EjBmqEL;AiB7pEC;;;;;EAMI,2BAAA;EjB8pEL;AgB5gED;EACE,kBAAA;EACA,mBAAA;EhB8gED;AgBj9DD;EAAA;IA1DI,aAAA;IACA,qBAAA;IACA,oBAAA;IACA,8CAAA;IACA,2BAAA;IhB+gED;EgBz9DH;IAlDM,kBAAA;IhB8gEH;EgB59DH;;;;;;IAzCY,qBAAA;IhB6gET;EgBp+DH;IAjCM,WAAA;IhBwgEH;EgBv+DH;;;;;;IAxBY,gBAAA;IhBugET;EgB/+DH;;;;;;IApBY,iBAAA;IhB2gET;EgBv/DH;;;;IAPY,kBAAA;IhBogET;EACF;AkB9tED;EACE,YAAA;EACA,WAAA;EACA,WAAA;EAIA,cAAA;ElB6tED;AkB1tED;EACE,gBAAA;EACA,aAAA;EACA,YAAA;EACA,qBAAA;EACA,iBAAA;EACA,sBAAA;EACA,gBAAA;EACA,WAAA;EACA,kCAAA;ElB4tED;AkBztED;EACE,uBAAA;EACA,iBAAA;EACA,oBAAA;EACA,mBAAA;ElB2tED;AkBhtED;Eb4BE,gCAAA;EACG,6BAAA;EACK,wBAAA;ELurET;AkBhtED;;EAEE,iBAAA;EACA,oBAAA;EACA,qBAAA;ElBktED;AkB9sED;EACE,gBAAA;ElBgtED;AkB5sED;EACE,gBAAA;EACA,aAAA;ElB8sED;AkB1sED;;EAEE,cAAA;ElB4sED;AkBxsED;;;EZxEE,sBAAA;EAEA,4CAAA;EACA,sBAAA;ENoxED;AkBxsED;EACE,gBAAA;EACA,kBAAA;EACA,iBAAA;EACA,yBAAA;EACA,gBAAA;ElB0sED;AkBhrED;EACE,gBAAA;EACA,aAAA;EACA,cAAA;EACA,mBAAA;EACA,iBAAA;EACA,yBAAA;EACA,gBAAA;EACA,2BAAA;EACA,wBAAA;EACA,2BAAA;EACA,oBAAA;EbzDA,0DAAA;EACQ,kDAAA;EAyHR,wFAAA;EACK,2EAAA;EACG,wEAAA;ELonET;AmB5vEC;EACE,uBAAA;EACA,YAAA;EdUF,wFAAA;EACQ,gFAAA;ELqvET;AKptEC;EACE,gBAAA;EACA,YAAA;ELstEH;AKptEC;EAA0B,gBAAA;ELutE3B;AKttEC;EAAgC,gBAAA;ELytEjC;AkBxrEC;;;EAGE,qBAAA;EACA,2BAAA;EACA,YAAA;ElB0rEH;AkBtrEC;EACE,cAAA;ElBwrEH;AkB5qED;EACE,0BAAA;ElB8qED;AkBlqED;;;;EAIE,mBAAA;EAEA,4BAAA;ElBmqED;AkBjqEC;;;;EACE,mBAAA;EACA,qBAAA;ElBsqEH;AkBpqEC;;;;EACE,mBAAA;EACA,sBAAA;ElByqEH;AkBpqED;;;;;;;;EAIE,yBAAA;ElB0qED;AkBxqEC;;;;;;;;EACE,kBAAA;ElBirEH;AkB/qEC;;;;;;;;EACE,mBAAA;ElBwrEH;AkB9qED;EACE,qBAAA;ElBgrED;AkBxqED;;EAEE,oBAAA;EACA,gBAAA;EACA,kBAAA;EACA,qBAAA;ElB0qED;AkB/qED;;EAQI,kBAAA;EACA,oBAAA;EACA,kBAAA;EACA,qBAAA;EACA,iBAAA;ElB2qEH;AkBxqED;;;;EAIE,oBAAA;EACA,oBAAA;EACA,oBAAA;ElB0qED;AkBvqED;;EAEE,kBAAA;ElByqED;AkBrqED;;EAEE,uBAAA;EACA,oBAAA;EACA,kBAAA;EACA,wBAAA;EACA,qBAAA;EACA,iBAAA;ElBuqED;AkBrqED;;EAEE,eAAA;EACA,mBAAA;ElBuqED;AkB9pEC;;;;;;EAGE,qBAAA;ElBmqEH;AkB7pEC;;;;EAEE,qBAAA;ElBiqEH;AkB3pEC;;;;EAGI,qBAAA;ElB8pEL;AkBnpED;EAEE,kBAAA;EACA,qBAAA;EAEA,kBAAA;ElBmpED;AkBjpEC;;EAEE,iBAAA;EACA,kBAAA;ElBmpEH;AkBzoED;;EChQE,cAAA;EACA,mBAAA;EACA,iBAAA;EACA,kBAAA;EACA,oBAAA;EnB64ED;AmB34EC;;EACE,cAAA;EACA,mBAAA;EnB84EH;AmB34EC;;;;EAEE,cAAA;EnB+4EH;AkBvpED;;ECrQE,cAAA;EACA,oBAAA;EACA,iBAAA;EACA,mBAAA;EACA,oBAAA;EnBg6ED;AmB95EC;;EACE,cAAA;EACA,mBAAA;EnBi6EH;AmB95EC;;;;EAEE,cAAA;EnBk6EH;AkBhqED;EAEE,oBAAA;ElBiqED;AkBnqED;EAMI,uBAAA;ElBgqEH;AkB5pED;EACE,oBAAA;EACA,QAAA;EACA,UAAA;EACA,YAAA;EACA,gBAAA;EACA,aAAA;EACA,cAAA;EACA,mBAAA;EACA,oBAAA;EACA,sBAAA;ElB8pED;AkB5pED;EACE,aAAA;EACA,cAAA;EACA,mBAAA;ElB8pED;AkB5pED;EACE,aAAA;EACA,cAAA;EACA,mBAAA;ElB8pED;AkB1pED;;;;;;;;;;ECrWI,gBAAA;EnB2gFH;AkBtqED;ECjWI,uBAAA;Ed+CF,0DAAA;EACQ,kDAAA;EL49ET;AmB1gFG;EACE,uBAAA;Ed4CJ,2EAAA;EACQ,mEAAA;ELi+ET;AkBhrED;ECvVI,gBAAA;EACA,uBAAA;EACA,2BAAA;EnB0gFH;AkBrrED;ECjVI,gBAAA;EnBygFH;AkBrrED;;;;;;;;;;ECxWI,gBAAA;EnByiFH;AkBjsED;ECpWI,uBAAA;Ed+CF,0DAAA;EACQ,kDAAA;EL0/ET;AmBxiFG;EACE,uBAAA;Ed4CJ,2EAAA;EACQ,mEAAA;EL+/ET;AkB3sED;EC1VI,gBAAA;EACA,uBAAA;EACA,2BAAA;EnBwiFH;AkBhtED;ECpVI,gBAAA;EnBuiFH;AkBhtED;;;;;;;;;;EC3WI,gBAAA;EnBukFH;AkB5tED;ECvWI,uBAAA;Ed+CF,0DAAA;EACQ,kDAAA;ELwhFT;AmBtkFG;EACE,uBAAA;Ed4CJ,2EAAA;EACQ,mEAAA;EL6hFT;AkBtuED;EC7VI,gBAAA;EACA,uBAAA;EACA,2BAAA;EnBskFH;AkB3uED;ECvVI,gBAAA;EnBqkFH;AkBvuEC;EACG,WAAA;ElByuEJ;AkBvuEC;EACG,QAAA;ElByuEJ;AkB/tED;EACE,gBAAA;EACA,iBAAA;EACA,qBAAA;EACA,gBAAA;ElBiuED;AkB7oED;EAAA;IA/DM,uBAAA;IACA,kBAAA;IACA,wBAAA;IlBgtEH;EkBnpEH;IAxDM,uBAAA;IACA,aAAA;IACA,wBAAA;IlB8sEH;EkBxpEH;IAjDM,uBAAA;IlB4sEH;EkB3pEH;IA7CM,uBAAA;IACA,wBAAA;IlB2sEH;EkB/pEH;;;IAvCQ,aAAA;IlB2sEL;EkBpqEH;IAjCM,aAAA;IlBwsEH;EkBvqEH;IA7BM,kBAAA;IACA,wBAAA;IlBusEH;EkB3qEH;;IApBM,uBAAA;IACA,eAAA;IACA,kBAAA;IACA,wBAAA;IlBmsEH;EkBlrEH;;IAdQ,iBAAA;IlBosEL;EkBtrEH;;IATM,oBAAA;IACA,gBAAA;IlBmsEH;EkB3rEH;IAHM,QAAA;IlBisEH;EACF;AkBvrED;;;;EASI,eAAA;EACA,kBAAA;EACA,kBAAA;ElBorEH;AkB/rED;;EAiBI,kBAAA;ElBkrEH;AkBnsED;EJleE,oBAAA;EACA,qBAAA;EdwqFD;AkBpqEC;EAAA;IANI,mBAAA;IACA,kBAAA;IACA,kBAAA;IlB8qEH;EACF;AkB9sED;EAwCI,aAAA;ElByqEH;AkB5pEC;EAAA;IAHM,qBAAA;IlBmqEL;EACF;AkB1pEC;EAAA;IAHM,kBAAA;IlBiqEL;EACF;AoBpsFD;EACE,uBAAA;EACA,kBAAA;EACA,qBAAA;EACA,oBAAA;EACA,wBAAA;EACA,gCAAA;MAAA,4BAAA;EACA,iBAAA;EACA,wBAAA;EACA,+BAAA;EACA,qBAAA;EC6BA,mBAAA;EACA,iBAAA;EACA,yBAAA;EACA,oBAAA;EhB4KA,2BAAA;EACG,wBAAA;EACC,uBAAA;EACI,mBAAA;EL+/ET;AoBvsFG;;;;;;EdrBF,sBAAA;EAEA,4CAAA;EACA,sBAAA;ENmuFD;AoB3sFC;;;EAGE,gBAAA;EACA,uBAAA;EpB6sFH;AoB1sFC;;EAEE,YAAA;EACA,wBAAA;Ef2BF,0DAAA;EACQ,kDAAA;ELkrFT;AoB1sFC;;;EAGE,qBAAA;EACA,sBAAA;EE9CF,eAAA;EAGA,2BAAA;EjB8DA,0BAAA;EACQ,kBAAA;EL4rFT;AoBtsFD;ECrDE,gBAAA;EACA,2BAAA;EACA,uBAAA;ErB8vFD;AqB5vFC;;;;;;EAME,gBAAA;EACA,2BAAA;EACI,uBAAA;ErB8vFP;AqB5vFC;;;EAGE,wBAAA;ErB8vFH;AqBzvFG;;;;;;;;;;;;;;;;;;EAME,2BAAA;EACI,uBAAA;ErBuwFT;AoB/uFD;ECnBI,gBAAA;EACA,2BAAA;ErBqwFH;AoBhvFD;ECxDE,gBAAA;EACA,2BAAA;EACA,uBAAA;ErB2yFD;AqBzyFC;;;;;;EAME,gBAAA;EACA,2BAAA;EACI,uBAAA;ErB2yFP;AqBzyFC;;;EAGE,wBAAA;ErB2yFH;AqBtyFG;;;;;;;;;;;;;;;;;;EAME,2BAAA;EACI,uBAAA;ErBozFT;AoBzxFD;ECtBI,gBAAA;EACA,2BAAA;ErBkzFH;AoBzxFD;EC5DE,gBAAA;EACA,2BAAA;EACA,uBAAA;ErBw1FD;AqBt1FC;;;;;;EAME,gBAAA;EACA,2BAAA;EACI,uBAAA;ErBw1FP;AqBt1FC;;;EAGE,wBAAA;ErBw1FH;AqBn1FG;;;;;;;;;;;;;;;;;;EAME,2BAAA;EACI,uBAAA;ErBi2FT;AoBl0FD;EC1BI,gBAAA;EACA,2BAAA;ErB+1FH;AoBl0FD;EChEE,gBAAA;EACA,2BAAA;EACA,uBAAA;ErBq4FD;AqBn4FC;;;;;;EAME,gBAAA;EACA,2BAAA;EACI,uBAAA;ErBq4FP;AqBn4FC;;;EAGE,wBAAA;ErBq4FH;AqBh4FG;;;;;;;;;;;;;;;;;;EAME,2BAAA;EACI,uBAAA;ErB84FT;AoB32FD;EC9BI,gBAAA;EACA,2BAAA;ErB44FH;AoB32FD;ECpEE,gBAAA;EACA,2BAAA;EACA,uBAAA;ErBk7FD;AqBh7FC;;;;;;EAME,gBAAA;EACA,2BAAA;EACI,uBAAA;ErBk7FP;AqBh7FC;;;EAGE,wBAAA;ErBk7FH;AqB76FG;;;;;;;;;;;;;;;;;;EAME,2BAAA;EACI,uBAAA;ErB27FT;AoBp5FD;EClCI,gBAAA;EACA,2BAAA;ErBy7FH;AoBp5FD;ECxEE,gBAAA;EACA,2BAAA;EACA,uBAAA;ErB+9FD;AqB79FC;;;;;;EAME,gBAAA;EACA,2BAAA;EACI,uBAAA;ErB+9FP;AqB79FC;;;EAGE,wBAAA;ErB+9FH;AqB19FG;;;;;;;;;;;;;;;;;;EAME,2BAAA;EACI,uBAAA;ErBw+FT;AoB77FD;ECtCI,gBAAA;EACA,2BAAA;ErBs+FH;AoBx7FD;EACE,gBAAA;EACA,qBAAA;EACA,kBAAA;EpB07FD;AoBx7FC;;;;;EAKE,+BAAA;Ef7BF,0BAAA;EACQ,kBAAA;ELw9FT;AoBz7FC;;;;EAIE,2BAAA;EpB27FH;AoBz7FC;;EAEE,gBAAA;EACA,4BAAA;EACA,+BAAA;EpB27FH;AoBv7FG;;;;EAEE,gBAAA;EACA,uBAAA;EpB27FL;AoBl7FD;;EC/EE,oBAAA;EACA,iBAAA;EACA,mBAAA;EACA,oBAAA;ErBqgGD;AoBr7FD;;ECnFE,mBAAA;EACA,iBAAA;EACA,kBAAA;EACA,oBAAA;ErB4gGD;AoBx7FD;;ECvFE,kBAAA;EACA,iBAAA;EACA,kBAAA;EACA,oBAAA;ErBmhGD;AoBv7FD;EACE,gBAAA;EACA,aAAA;EpBy7FD;AoBr7FD;EACE,iBAAA;EpBu7FD;AoBh7FC;;;EACE,aAAA;EpBo7FH;AuBxkGD;EACE,YAAA;ElBoLA,0CAAA;EACK,qCAAA;EACG,kCAAA;ELu5FT;AuB3kGC;EACE,YAAA;EvB6kGH;AuBzkGD;EACE,eAAA;EACA,oBAAA;EvB2kGD;AuBzkGC;EAAY,gBAAA;EAAgB,qBAAA;EvB6kG7B;AuB5kGC;EAAY,oBAAA;EvB+kGb;AuB9kGC;EAAY,0BAAA;EvBilGb;AuB9kGD;EACE,oBAAA;EACA,WAAA;EACA,kBAAA;ElBsKA,iDAAA;EACQ,4CAAA;KAAA,yCAAA;EAOR,oCAAA;EACQ,+BAAA;KAAA,4BAAA;EAGR,0CAAA;EACQ,qCAAA;KAAA,kCAAA;ELm6FT;AwB7mGD;EACE,uBAAA;EACA,UAAA;EACA,WAAA;EACA,kBAAA;EACA,wBAAA;EACA,uBAAA;EACA,qCAAA;EACA,oCAAA;ExB+mGD;AwB3mGD;EACE,oBAAA;ExB6mGD;AwBzmGD;EACE,YAAA;ExB2mGD;AwBvmGD;EACE,oBAAA;EACA,WAAA;EACA,SAAA;EACA,eAAA;EACA,eAAA;EACA,aAAA;EACA,kBAAA;EACA,gBAAA;EACA,iBAAA;EACA,kBAAA;EACA,iBAAA;EACA,kBAAA;EACA,2BAAA;EACA,2BAAA;EACA,uCAAA;EACA,oBAAA;EnBwBA,qDAAA;EACQ,6CAAA;EmBvBR,sCAAA;UAAA,8BAAA;ExB0mGD;AwBrmGC;EACE,UAAA;EACA,YAAA;ExBumGH;AwBhoGD;ECvBE,aAAA;EACA,eAAA;EACA,kBAAA;EACA,2BAAA;EzB0pGD;AwBtoGD;EAmCI,gBAAA;EACA,mBAAA;EACA,aAAA;EACA,qBAAA;EACA,yBAAA;EACA,gBAAA;EACA,qBAAA;ExBsmGH;AwBhmGC;;EAEE,uBAAA;EACA,gBAAA;EACA,2BAAA;ExBkmGH;AwB5lGC;;;EAGE,gBAAA;EACA,uBAAA;EACA,YAAA;EACA,2BAAA;ExB8lGH;AwBrlGC;;;EAGE,gBAAA;ExBulGH;AwBnlGC;;EAEE,uBAAA;EACA,+BAAA;EACA,wBAAA;EEzGF,qEAAA;EF2GE,qBAAA;ExBqlGH;AwBhlGD;EAGI,gBAAA;ExBglGH;AwBnlGD;EAQI,YAAA;ExB8kGH;AwBtkGD;EACE,YAAA;EACA,UAAA;ExBwkGD;AwBhkGD;EACE,SAAA;EACA,aAAA;ExBkkGD;AwB9jGD;EACE,gBAAA;EACA,mBAAA;EACA,iBAAA;EACA,yBAAA;EACA,gBAAA;EACA,qBAAA;ExBgkGD;AwB5jGD;EACE,iBAAA;EACA,SAAA;EACA,UAAA;EACA,WAAA;EACA,QAAA;EACA,cAAA;ExB8jGD;AwB1jGD;EACE,UAAA;EACA,YAAA;ExB4jGD;AwBpjGD;;EAII,eAAA;EACA,0BAAA;EACA,aAAA;ExBojGH;AwB1jGD;;EAUI,WAAA;EACA,cAAA;EACA,oBAAA;ExBojGH;AwB/hGD;EAXE;IAnEA,YAAA;IACA,UAAA;IxBinGC;EwB/iGD;IAzDA,SAAA;IACA,aAAA;IxB2mGC;EACF;A2BzvGD;;EAEE,oBAAA;EACA,uBAAA;EACA,wBAAA;E3B2vGD;A2B/vGD;;EAMI,oBAAA;EACA,aAAA;E3B6vGH;A2B3vGG;;;;;;;;EAIE,YAAA;E3BiwGL;A2B/vGG;;EAEE,YAAA;E3BiwGL;A2B3vGD;;;;EAKI,mBAAA;E3B4vGH;A2BvvGD;EACE,mBAAA;E3ByvGD;A2B1vGD;;EAMI,aAAA;E3BwvGH;A2B9vGD;;;EAWI,kBAAA;E3BwvGH;A2BpvGD;EACE,kBAAA;E3BsvGD;A2BlvGD;EACE,gBAAA;E3BovGD;A2BnvGC;ECrDA,+BAAA;EACG,4BAAA;E5B2yGJ;A2BlvGD;;EClDE,8BAAA;EACG,2BAAA;E5BwyGJ;A2BjvGD;EACE,aAAA;E3BmvGD;A2BjvGD;EACE,kBAAA;E3BmvGD;A2BjvGD;;ECtEE,+BAAA;EACG,4BAAA;E5B2zGJ;A2BhvGD;ECpEE,8BAAA;EACG,2BAAA;E5BuzGJ;A2B/uGD;;EAEE,YAAA;E3BivGD;A2BhuGD;EACE,mBAAA;EACA,oBAAA;E3BkuGD;A2BhuGD;EACE,oBAAA;EACA,qBAAA;E3BkuGD;A2B7tGD;EtBlDE,0DAAA;EACQ,kDAAA;ELkxGT;A2B7tGC;EtBtDA,0BAAA;EACQ,kBAAA;ELsxGT;A2B1tGD;EACE,gBAAA;E3B4tGD;A2BztGD;EACE,yBAAA;EACA,wBAAA;E3B2tGD;A2BxtGD;EACE,yBAAA;E3B0tGD;A2BntGD;;;EAII,gBAAA;EACA,aAAA;EACA,aAAA;EACA,iBAAA;E3BotGH;A2B3tGD;EAcM,aAAA;E3BgtGL;A2B9tGD;;;;EAsBI,kBAAA;EACA,gBAAA;E3B8sGH;A2BzsGC;EACE,kBAAA;E3B2sGH;A2BzsGC;EACE,8BAAA;ECvKF,+BAAA;EACC,8BAAA;E5Bm3GF;A2B1sGC;EACE,gCAAA;ECnLF,4BAAA;EACC,2BAAA;E5Bg4GF;A2B1sGD;EACE,kBAAA;E3B4sGD;A2B1sGD;;EClLE,+BAAA;EACC,8BAAA;E5Bg4GF;A2BzsGD;EChME,4BAAA;EACC,2BAAA;E5B44GF;A2BrsGD;EACE,gBAAA;EACA,aAAA;EACA,qBAAA;EACA,2BAAA;E3BusGD;A2B3sGD;;EAOI,aAAA;EACA,qBAAA;EACA,WAAA;E3BwsGH;A2BjtGD;EAYI,aAAA;E3BwsGH;A2BptGD;EAgBI,YAAA;E3BusGH;A2BtrGD;;;;EAKM,oBAAA;EACA,wBAAA;EACA,sBAAA;E3BurGL;A6Bp6GD;EACE,oBAAA;EACA,gBAAA;EACA,2BAAA;E7Bs6GD;A6Bn6GC;EACE,aAAA;EACA,iBAAA;EACA,kBAAA;E7Bq6GH;A6B96GD;EAeI,oBAAA;EACA,YAAA;EAKA,aAAA;EAEA,aAAA;EACA,kBAAA;E7B65GH;A6Bp5GD;;;EV8BE,cAAA;EACA,oBAAA;EACA,iBAAA;EACA,mBAAA;EACA,oBAAA;EnB23GD;AmBz3GC;;;EACE,cAAA;EACA,mBAAA;EnB63GH;AmB13GC;;;;;;EAEE,cAAA;EnBg4GH;A6Bt6GD;;;EVyBE,cAAA;EACA,mBAAA;EACA,iBAAA;EACA,kBAAA;EACA,oBAAA;EnBk5GD;AmBh5GC;;;EACE,cAAA;EACA,mBAAA;EnBo5GH;AmBj5GC;;;;;;EAEE,cAAA;EnBu5GH;A6Bp7GD;;;EAGE,qBAAA;E7Bs7GD;A6Bp7GC;;;EACE,kBAAA;E7Bw7GH;A6Bp7GD;;EAEE,WAAA;EACA,qBAAA;EACA,wBAAA;E7Bs7GD;A6Bj7GD;EACE,mBAAA;EACA,iBAAA;EACA,qBAAA;EACA,gBAAA;EACA,gBAAA;EACA,oBAAA;EACA,2BAAA;EACA,2BAAA;EACA,oBAAA;E7Bm7GD;A6Bh7GC;EACE,mBAAA;EACA,iBAAA;EACA,oBAAA;E7Bk7GH;A6Bh7GC;EACE,oBAAA;EACA,iBAAA;EACA,oBAAA;E7Bk7GH;A6Bt8GD;;EA0BI,eAAA;E7Bg7GH;A6B36GD;;;;;;;EDhGE,+BAAA;EACG,4BAAA;E5BohHJ;A6B56GD;EACE,iBAAA;E7B86GD;A6B56GD;;;;;;;EDpGE,8BAAA;EACG,2BAAA;E5ByhHJ;A6B76GD;EACE,gBAAA;E7B+6GD;A6B16GD;EACE,oBAAA;EAGA,cAAA;EACA,qBAAA;E7B06GD;A6B/6GD;EAUI,oBAAA;E7Bw6GH;A6Bl7GD;EAYM,mBAAA;E7By6GL;A6Bt6GG;;;EAGE,YAAA;E7Bw6GL;A6Bn6GC;;EAGI,oBAAA;E7Bo6GL;A6Bj6GC;;EAGI,mBAAA;E7Bk6GL;A8B5jHD;EACE,kBAAA;EACA,iBAAA;EACA,kBAAA;E9B8jHD;A8BjkHD;EAOI,oBAAA;EACA,gBAAA;E9B6jHH;A8BrkHD;EAWM,oBAAA;EACA,gBAAA;EACA,oBAAA;E9B6jHL;A8B5jHK;;EAEE,uBAAA;EACA,2BAAA;E9B8jHP;A8BzjHG;EACE,gBAAA;E9B2jHL;A8BzjHK;;EAEE,gBAAA;EACA,uBAAA;EACA,+BAAA;EACA,qBAAA;E9B2jHP;A8BpjHG;;;EAGE,2BAAA;EACA,uBAAA;E9BsjHL;A8B/lHD;ELHE,aAAA;EACA,eAAA;EACA,kBAAA;EACA,2BAAA;EzBqmHD;A8BrmHD;EA0DI,iBAAA;E9B8iHH;A8BriHD;EACE,kCAAA;E9BuiHD;A8BxiHD;EAGI,aAAA;EAEA,qBAAA;E9BuiHH;A8B5iHD;EASM,mBAAA;EACA,yBAAA;EACA,+BAAA;EACA,4BAAA;E9BsiHL;A8BriHK;EACE,uCAAA;E9BuiHP;A8BjiHK;;;EAGE,gBAAA;EACA,2BAAA;EACA,2BAAA;EACA,kCAAA;EACA,iBAAA;E9BmiHP;A8B9hHC;EAqDA,aAAA;EA8BA,kBAAA;E9B+8GD;A8BliHC;EAwDE,aAAA;E9B6+GH;A8BriHC;EA0DI,oBAAA;EACA,oBAAA;E9B8+GL;A8BziHC;EAgEE,WAAA;EACA,YAAA;E9B4+GH;A8Bh+GD;EAAA;IAPM,qBAAA;IACA,WAAA;I9B2+GH;E8Br+GH;IAJQ,kBAAA;I9B4+GL;EACF;A8BtjHC;EAuFE,iBAAA;EACA,oBAAA;E9Bk+GH;A8B1jHC;;;EA8FE,2BAAA;E9Bi+GH;A8Bn9GD;EAAA;IATM,kCAAA;IACA,4BAAA;I9Bg+GH;E8Bx9GH;;;IAHM,8BAAA;I9Bg+GH;EACF;A8BjkHD;EAEI,aAAA;E9BkkHH;A8BpkHD;EAMM,oBAAA;E9BikHL;A8BvkHD;EASM,kBAAA;E9BikHL;A8B5jHK;;;EAGE,gBAAA;EACA,2BAAA;E9B8jHP;A8BtjHD;EAEI,aAAA;E9BujHH;A8BzjHD;EAIM,iBAAA;EACA,gBAAA;E9BwjHL;A8B5iHD;EACE,aAAA;E9B8iHD;A8B/iHD;EAII,aAAA;E9B8iHH;A8BljHD;EAMM,oBAAA;EACA,oBAAA;E9B+iHL;A8BtjHD;EAYI,WAAA;EACA,YAAA;E9B6iHH;A8BjiHD;EAAA;IAPM,qBAAA;IACA,WAAA;I9B4iHH;E8BtiHH;IAJQ,kBAAA;I9B6iHL;EACF;A8BriHD;EACE,kBAAA;E9BuiHD;A8BxiHD;EAKI,iBAAA;EACA,oBAAA;E9BsiHH;A8B5iHD;;;EAYI,2BAAA;E9BqiHH;A8BvhHD;EAAA;IATM,kCAAA;IACA,4BAAA;I9BoiHH;E8B5hHH;;;IAHM,8BAAA;I9BoiHH;EACF;A8B3hHD;EAEI,eAAA;EACA,oBAAA;E9B4hHH;A8B/hHD;EAMI,gBAAA;EACA,qBAAA;E9B4hHH;A8BnhHD;EAEE,kBAAA;EF7OA,4BAAA;EACC,2BAAA;E5BkwHF;A+B5vHD;EACE,oBAAA;EACA,kBAAA;EACA,qBAAA;EACA,+BAAA;E/B8vHD;A+BtvHD;EAAA;IAFI,oBAAA;I/B4vHD;EACF;A+B7uHD;EAAA;IAFI,aAAA;I/BmvHD;EACF;A+BruHD;EACE,qBAAA;EACA,qBAAA;EACA,oBAAA;EACA,mCAAA;EACA,4DAAA;UAAA,oDAAA;EAEA,mCAAA;E/BsuHD;A+BpuHC;EACE,kBAAA;E/BsuHH;A+BzsHD;EAAA;IAzBI,aAAA;IACA,eAAA;IACA,0BAAA;YAAA,kBAAA;I/BsuHD;E+BpuHC;IACE,2BAAA;IACA,gCAAA;IACA,yBAAA;IACA,mBAAA;IACA,8BAAA;I/BsuHH;E+BnuHC;IACE,qBAAA;I/BquHH;E+BhuHC;;;IAGE,iBAAA;IACA,kBAAA;I/BkuHH;EACF;A+B9tHD;;EAGI,mBAAA;E/B+tHH;A+B1tHC;EAAA;;IAFI,mBAAA;I/BiuHH;EACF;A+BxtHD;;;;EAII,qBAAA;EACA,oBAAA;E/B0tHH;A+BptHC;EAAA;;;;IAHI,iBAAA;IACA,gBAAA;I/B8tHH;EACF;A+BltHD;EACE,eAAA;EACA,uBAAA;E/BotHD;A+B/sHD;EAAA;IAFI,kBAAA;I/BqtHD;EACF;A+BjtHD;;EAEE,iBAAA;EACA,UAAA;EACA,SAAA;EACA,eAAA;E/BmtHD;A+B7sHD;EAAA;;IAFI,kBAAA;I/BotHD;EACF;A+BltHD;EACE,QAAA;EACA,uBAAA;E/BotHD;A+BltHD;EACE,WAAA;EACA,kBAAA;EACA,uBAAA;E/BotHD;A+B9sHD;EACE,aAAA;EACA,oBAAA;EACA,iBAAA;EACA,mBAAA;EACA,cAAA;E/BgtHD;A+B9sHC;;EAEE,uBAAA;E/BgtHH;A+BztHD;EAaI,gBAAA;E/B+sHH;A+BtsHD;EALI;;IAEE,oBAAA;I/B8sHH;EACF;A+BpsHD;EACE,oBAAA;EACA,cAAA;EACA,oBAAA;EACA,mBAAA;EC/LA,iBAAA;EACA,oBAAA;EDgMA,+BAAA;EACA,wBAAA;EACA,+BAAA;EACA,oBAAA;E/BusHD;A+BnsHC;EACE,YAAA;E/BqsHH;A+BntHD;EAmBI,gBAAA;EACA,aAAA;EACA,aAAA;EACA,oBAAA;E/BmsHH;A+BztHD;EAyBI,iBAAA;E/BmsHH;A+B7rHD;EAAA;IAFI,eAAA;I/BmsHD;EACF;A+B1rHD;EACE,qBAAA;E/B4rHD;A+B7rHD;EAII,mBAAA;EACA,sBAAA;EACA,mBAAA;E/B4rHH;A+BjqHC;EAAA;IArBI,kBAAA;IACA,aAAA;IACA,aAAA;IACA,eAAA;IACA,+BAAA;IACA,WAAA;IACA,0BAAA;YAAA,kBAAA;I/B0rHH;E+B3qHD;;IAZM,4BAAA;I/B2rHL;E+B/qHD;IATM,mBAAA;I/B2rHL;E+B1rHK;;IAEE,wBAAA;I/B4rHP;EACF;A+B1qHD;EAAA;IAXI,aAAA;IACA,WAAA;I/ByrHD;E+B/qHH;IAPM,aAAA;I/ByrHH;E+BlrHH;IALQ,mBAAA;IACA,sBAAA;I/B0rHL;EACF;A+B/qHD;EACE,oBAAA;EACA,qBAAA;EACA,oBAAA;EACA,mCAAA;EACA,sCAAA;E1B/NA,8FAAA;EACQ,sFAAA;E2B/DR,iBAAA;EACA,oBAAA;EhCi9HD;AkB/+GD;EAAA;IA/DM,uBAAA;IACA,kBAAA;IACA,wBAAA;IlBkjHH;EkBr/GH;IAxDM,uBAAA;IACA,aAAA;IACA,wBAAA;IlBgjHH;EkB1/GH;IAjDM,uBAAA;IlB8iHH;EkB7/GH;IA7CM,uBAAA;IACA,wBAAA;IlB6iHH;EkBjgHH;;;IAvCQ,aAAA;IlB6iHL;EkBtgHH;IAjCM,aAAA;IlB0iHH;EkBzgHH;IA7BM,kBAAA;IACA,wBAAA;IlByiHH;EkB7gHH;;IApBM,uBAAA;IACA,eAAA;IACA,kBAAA;IACA,wBAAA;IlBqiHH;EkBphHH;;IAdQ,iBAAA;IlBsiHL;EkBxhHH;;IATM,oBAAA;IACA,gBAAA;IlBqiHH;EkB7hHH;IAHM,QAAA;IlBmiHH;EACF;A+BxtHC;EAAA;IANI,oBAAA;I/BkuHH;E+BhuHG;IACE,kBAAA;I/BkuHL;EACF;A+BjtHD;EAAA;IARI,aAAA;IACA,WAAA;IACA,gBAAA;IACA,iBAAA;IACA,gBAAA;IACA,mBAAA;I1B1PF,0BAAA;IACQ,kBAAA;ILw9HP;EACF;A+BvtHD;EACE,eAAA;EHrUA,4BAAA;EACC,2BAAA;E5B+hIF;A+BvtHD;EHjUE,+BAAA;EACC,8BAAA;E5B2hIF;A+BltHD;EC/UE,iBAAA;EACA,oBAAA;EhCoiID;A+BntHC;EClVA,kBAAA;EACA,qBAAA;EhCwiID;A+BptHC;ECrVA,kBAAA;EACA,qBAAA;EhC4iID;A+B9sHD;EC/VE,kBAAA;EACA,qBAAA;EhCgjID;A+B1sHD;EAAA;IAJI,aAAA;IACA,mBAAA;IACA,oBAAA;I/BktHD;EACF;A+BzrHD;EAZE;IEvWA,wBAAA;IjCgjIC;E+BxsHD;IE3WA,yBAAA;IF6WE,qBAAA;I/B0sHD;E+B5sHD;IAKI,iBAAA;I/B0sHH;EACF;A+BjsHD;EACE,2BAAA;EACA,uBAAA;E/BmsHD;A+BrsHD;EAKI,gBAAA;E/BmsHH;A+BlsHG;;EAEE,gBAAA;EACA,+BAAA;E/BosHL;A+B7sHD;EAcI,gBAAA;E/BksHH;A+BhtHD;EAmBM,gBAAA;E/BgsHL;A+B9rHK;;EAEE,gBAAA;EACA,+BAAA;E/BgsHP;A+B5rHK;;;EAGE,gBAAA;EACA,2BAAA;E/B8rHP;A+B1rHK;;;EAGE,gBAAA;EACA,+BAAA;E/B4rHP;A+BpuHD;EA8CI,uBAAA;E/ByrHH;A+BxrHG;;EAEE,2BAAA;E/B0rHL;A+B3uHD;EAoDM,2BAAA;E/B0rHL;A+B9uHD;;EA0DI,uBAAA;E/BwrHH;A+BjrHK;;;EAGE,2BAAA;EACA,gBAAA;E/BmrHP;A+BlpHC;EAAA;IAzBQ,gBAAA;I/B+qHP;E+B9qHO;;IAEE,gBAAA;IACA,+BAAA;I/BgrHT;E+B5qHO;;;IAGE,gBAAA;IACA,2BAAA;I/B8qHT;E+B1qHO;;;IAGE,gBAAA;IACA,+BAAA;I/B4qHT;EACF;A+B9wHD;EA8GI,gBAAA;E/BmqHH;A+BlqHG;EACE,gBAAA;E/BoqHL;A+BpxHD;EAqHI,gBAAA;E/BkqHH;A+BjqHG;;EAEE,gBAAA;E/BmqHL;A+B/pHK;;;;EAEE,gBAAA;E/BmqHP;A+B3pHD;EACE,2BAAA;EACA,uBAAA;E/B6pHD;A+B/pHD;EAKI,gBAAA;E/B6pHH;A+B5pHG;;EAEE,gBAAA;EACA,+BAAA;E/B8pHL;A+BvqHD;EAcI,gBAAA;E/B4pHH;A+B1qHD;EAmBM,gBAAA;E/B0pHL;A+BxpHK;;EAEE,gBAAA;EACA,+BAAA;E/B0pHP;A+BtpHK;;;EAGE,gBAAA;EACA,2BAAA;E/BwpHP;A+BppHK;;;EAGE,gBAAA;EACA,+BAAA;E/BspHP;A+B9rHD;EA+CI,uBAAA;E/BkpHH;A+BjpHG;;EAEE,2BAAA;E/BmpHL;A+BrsHD;EAqDM,2BAAA;E/BmpHL;A+BxsHD;;EA2DI,uBAAA;E/BipHH;A+B3oHK;;;EAGE,2BAAA;EACA,gBAAA;E/B6oHP;A+BtmHC;EAAA;IA/BQ,uBAAA;I/ByoHP;E+B1mHD;IA5BQ,2BAAA;I/ByoHP;E+B7mHD;IAzBQ,gBAAA;I/ByoHP;E+BxoHO;;IAEE,gBAAA;IACA,+BAAA;I/B0oHT;E+BtoHO;;;IAGE,gBAAA;IACA,2BAAA;I/BwoHT;E+BpoHO;;;IAGE,gBAAA;IACA,+BAAA;I/BsoHT;EACF;A+B9uHD;EA+GI,gBAAA;E/BkoHH;A+BjoHG;EACE,gBAAA;E/BmoHL;A+BpvHD;EAsHI,gBAAA;E/BioHH;A+BhoHG;;EAEE,gBAAA;E/BkoHL;A+B9nHK;;;;EAEE,gBAAA;E/BkoHP;AkC3wID;EACE,mBAAA;EACA,qBAAA;EACA,kBAAA;EACA,2BAAA;EACA,oBAAA;ElC6wID;AkClxID;EAQI,uBAAA;ElC6wIH;AkCrxID;EAWM,mBAAA;EACA,gBAAA;EACA,gBAAA;ElC6wIL;AkC1xID;EAkBI,gBAAA;ElC2wIH;AmC/xID;EACE,uBAAA;EACA,iBAAA;EACA,gBAAA;EACA,oBAAA;EnCiyID;AmCryID;EAOI,iBAAA;EnCiyIH;AmCxyID;;EAUM,oBAAA;EACA,aAAA;EACA,mBAAA;EACA,yBAAA;EACA,uBAAA;EACA,gBAAA;EACA,2BAAA;EACA,2BAAA;EACA,mBAAA;EnCkyIL;AmChyIG;;EAGI,gBAAA;EPXN,gCAAA;EACG,6BAAA;E5B6yIJ;AmC/xIG;;EPvBF,iCAAA;EACG,8BAAA;E5B0zIJ;AmC1xIG;;;;EAEE,gBAAA;EACA,2BAAA;EACA,uBAAA;EnC8xIL;AmCxxIG;;;;;;EAGE,YAAA;EACA,gBAAA;EACA,2BAAA;EACA,uBAAA;EACA,iBAAA;EnC6xIL;AmCn1ID;;;;;;EAiEM,gBAAA;EACA,2BAAA;EACA,uBAAA;EACA,qBAAA;EnC0xIL;AmCjxID;;EC1EM,oBAAA;EACA,iBAAA;EpC+1IL;AoC71IG;;ERMF,gCAAA;EACG,6BAAA;E5B21IJ;AoC51IG;;ERRF,iCAAA;EACG,8BAAA;E5Bw2IJ;AmC3xID;;EC/EM,mBAAA;EACA,iBAAA;EpC82IL;AoC52IG;;ERMF,gCAAA;EACG,6BAAA;E5B02IJ;AoC32IG;;ERRF,iCAAA;EACG,8BAAA;E5Bu3IJ;AqC13ID;EACE,iBAAA;EACA,gBAAA;EACA,kBAAA;EACA,oBAAA;ErC43ID;AqCh4ID;EAOI,iBAAA;ErC43IH;AqCn4ID;;EAUM,uBAAA;EACA,mBAAA;EACA,2BAAA;EACA,2BAAA;EACA,qBAAA;ErC63IL;AqC34ID;;EAmBM,uBAAA;EACA,2BAAA;ErC43IL;AqCh5ID;;EA2BM,cAAA;ErCy3IL;AqCp5ID;;EAkCM,aAAA;ErCs3IL;AqCx5ID;;;;EA2CM,gBAAA;EACA,2BAAA;EACA,qBAAA;ErCm3IL;AsCj6ID;EACE,iBAAA;EACA,yBAAA;EACA,gBAAA;EACA,mBAAA;EACA,gBAAA;EACA,gBAAA;EACA,oBAAA;EACA,qBAAA;EACA,0BAAA;EACA,sBAAA;EtCm6ID;AsC/5IG;;EAEE,gBAAA;EACA,uBAAA;EACA,iBAAA;EtCi6IL;AsC55IC;EACE,eAAA;EtC85IH;AsC15IC;EACE,oBAAA;EACA,WAAA;EtC45IH;AsCr5ID;ECtCE,2BAAA;EvC87ID;AuC37IG;;EAEE,2BAAA;EvC67IL;AsCx5ID;EC1CE,2BAAA;EvCq8ID;AuCl8IG;;EAEE,2BAAA;EvCo8IL;AsC35ID;EC9CE,2BAAA;EvC48ID;AuCz8IG;;EAEE,2BAAA;EvC28IL;AsC95ID;EClDE,2BAAA;EvCm9ID;AuCh9IG;;EAEE,2BAAA;EvCk9IL;AsCj6ID;ECtDE,2BAAA;EvC09ID;AuCv9IG;;EAEE,2BAAA;EvCy9IL;AsCp6ID;EC1DE,2BAAA;EvCi+ID;AuC99IG;;EAEE,2BAAA;EvCg+IL;AwCl+ID;EACE,uBAAA;EACA,iBAAA;EACA,kBAAA;EACA,iBAAA;EACA,mBAAA;EACA,gBAAA;EACA,gBAAA;EACA,0BAAA;EACA,qBAAA;EACA,oBAAA;EACA,2BAAA;EACA,qBAAA;ExCo+ID;AwCj+IC;EACE,eAAA;ExCm+IH;AwC/9IC;EACE,oBAAA;EACA,WAAA;ExCi+IH;AwC/9IC;EACE,QAAA;EACA,kBAAA;ExCi+IH;AwC59IG;;EAEE,gBAAA;EACA,uBAAA;EACA,iBAAA;ExC89IL;AwCz9IC;;EAEE,gBAAA;EACA,2BAAA;ExC29IH;AwCz9IC;EACE,kBAAA;ExC29IH;AyC1gJD;EACE,oBAAA;EACA,qBAAA;EACA,gBAAA;EACA,2BAAA;EzC4gJD;AyChhJD;;EAQI,gBAAA;EzC4gJH;AyCphJD;EAWI,qBAAA;EACA,iBAAA;EACA,kBAAA;EzC4gJH;AyCzhJD;EAiBI,2BAAA;EzC2gJH;AyCxgJC;;EAEE,oBAAA;EzC0gJH;AyChiJD;EA0BI,iBAAA;EzCygJH;AyCz/ID;EAAA;IAZI,iBAAA;IzCygJD;EyCvgJC;IACE,oBAAA;IACA,qBAAA;IzCygJH;EyCjgJH;;IAHM,iBAAA;IzCwgJH;EACF;A0C/iJD;EACE,gBAAA;EACA,cAAA;EACA,qBAAA;EACA,yBAAA;EACA,2BAAA;EACA,2BAAA;EACA,oBAAA;ErCiLA,6CAAA;EACK,wCAAA;EACG,qCAAA;ELi4IT;A0C3jJD;;EAaI,mBAAA;EACA,oBAAA;E1CkjJH;A0C9iJC;;;EAGE,uBAAA;E1CgjJH;A0CrkJD;EA0BI,cAAA;EACA,gBAAA;E1C8iJH;A2CvkJD;EACE,eAAA;EACA,qBAAA;EACA,+BAAA;EACA,oBAAA;E3CykJD;A2C7kJD;EAQI,eAAA;EAEA,gBAAA;E3CukJH;A2CjlJD;EAcI,mBAAA;E3CskJH;A2CplJD;;EAoBI,kBAAA;E3CokJH;A2CxlJD;EAuBI,iBAAA;E3CokJH;A2C5jJD;;EAEE,qBAAA;E3C8jJD;A2ChkJD;;EAMI,oBAAA;EACA,WAAA;EACA,cAAA;EACA,gBAAA;E3C8jJH;A2CtjJD;ECrDE,2BAAA;EACA,uBAAA;EACA,gBAAA;E5C8mJD;A2C3jJD;EChDI,2BAAA;E5C8mJH;A2C9jJD;EC7CI,gBAAA;E5C8mJH;A2C9jJD;ECxDE,2BAAA;EACA,uBAAA;EACA,gBAAA;E5CynJD;A2CnkJD;ECnDI,2BAAA;E5CynJH;A2CtkJD;EChDI,gBAAA;E5CynJH;A2CtkJD;EC3DE,2BAAA;EACA,uBAAA;EACA,gBAAA;E5CooJD;A2C3kJD;ECtDI,2BAAA;E5CooJH;A2C9kJD;ECnDI,gBAAA;E5CooJH;A2C9kJD;EC9DE,2BAAA;EACA,uBAAA;EACA,gBAAA;E5C+oJD;A2CnlJD;ECzDI,2BAAA;E5C+oJH;A2CtlJD;ECtDI,gBAAA;E5C+oJH;A6CjpJD;EACE;IAAQ,6BAAA;I7CopJP;E6CnpJD;IAAQ,0BAAA;I7CspJP;EACF;A6CnpJD;EACE;IAAQ,6BAAA;I7CspJP;E6CrpJD;IAAQ,0BAAA;I7CwpJP;EACF;A6C3pJD;EACE;IAAQ,6BAAA;I7CspJP;E6CrpJD;IAAQ,0BAAA;I7CwpJP;EACF;A6CjpJD;EACE,kBAAA;EACA,cAAA;EACA,qBAAA;EACA,2BAAA;EACA,oBAAA;ExCsCA,wDAAA;EACQ,gDAAA;EL8mJT;A6ChpJD;EACE,aAAA;EACA,WAAA;EACA,cAAA;EACA,iBAAA;EACA,mBAAA;EACA,gBAAA;EACA,oBAAA;EACA,2BAAA;ExCyBA,wDAAA;EACQ,gDAAA;EAyHR,qCAAA;EACK,gCAAA;EACG,6BAAA;ELkgJT;A6C7oJD;;ECCI,+MAAA;EACA,0MAAA;EACA,uMAAA;EDAF,oCAAA;UAAA,4BAAA;E7CipJD;A6C1oJD;;ExC5CE,4DAAA;EACK,uDAAA;EACG,oDAAA;EL0rJT;A6CvoJD;EErEE,2BAAA;E/C+sJD;A+C5sJC;EDgDE,+MAAA;EACA,0MAAA;EACA,uMAAA;E9C+pJH;A6C3oJD;EEzEE,2BAAA;E/CutJD;A+CptJC;EDgDE,+MAAA;EACA,0MAAA;EACA,uMAAA;E9CuqJH;A6C/oJD;EE7EE,2BAAA;E/C+tJD;A+C5tJC;EDgDE,+MAAA;EACA,0MAAA;EACA,uMAAA;E9C+qJH;A6CnpJD;EEjFE,2BAAA;E/CuuJD;A+CpuJC;EDgDE,+MAAA;EACA,0MAAA;EACA,uMAAA;E9CurJH;AgD/uJD;EAEE,kBAAA;EhDgvJD;AgD9uJC;EACE,eAAA;EhDgvJH;AgD5uJD;;EAEE,oBAAA;EhD8uJD;AgD3uJD;;EAEE,qBAAA;EhD6uJD;AgD1uJD;;;EAGE,qBAAA;EACA,qBAAA;EhD4uJD;AgDzuJD;EACE,wBAAA;EhD2uJD;AgDxuJD;EACE,wBAAA;EhD0uJD;AgDtuJD;EACE,eAAA;EACA,oBAAA;EhDwuJD;AgDluJD;EACE,iBAAA;EACA,kBAAA;EhDouJD;AiDxwJD;EAEE,qBAAA;EACA,iBAAA;EjDywJD;AiDjwJD;EACE,oBAAA;EACA,gBAAA;EACA,oBAAA;EAEA,qBAAA;EACA,2BAAA;EACA,2BAAA;EjDkwJD;AiD/vJC;ErB3BA,8BAAA;EACC,6BAAA;E5B6xJF;AiDhwJC;EACE,kBAAA;ErBvBF,iCAAA;EACC,gCAAA;E5B0xJF;AiDlxJD;EAoBI,cAAA;EjDiwJH;AiDrxJD;EAuBI,mBAAA;EjDiwJH;AiDvvJD;EACE,gBAAA;EjDyvJD;AiD1vJD;EAII,gBAAA;EjDyvJH;AiDrvJC;;EAEE,uBAAA;EACA,gBAAA;EACA,2BAAA;EjDuvJH;AiDjvJC;;;EAGE,2BAAA;EACA,gBAAA;EACA,qBAAA;EjDmvJH;AiDxvJC;;;EASI,gBAAA;EjDovJL;AiD7vJC;;;EAYI,gBAAA;EjDsvJL;AiDjvJC;;;EAGE,YAAA;EACA,gBAAA;EACA,2BAAA;EACA,uBAAA;EjDmvJH;AiDzvJC;;;;;;;;;EAYI,gBAAA;EjDwvJL;AiDpwJC;;;EAeI,gBAAA;EjD0vJL;AkD91JC;EACE,gBAAA;EACA,2BAAA;ElDg2JH;AkD91JG;EACE,gBAAA;ElDg2JL;AkDj2JG;EAII,gBAAA;ElDg2JP;AkD71JK;;EAEE,gBAAA;EACA,2BAAA;ElD+1JP;AkD71JK;;;EAGE,aAAA;EACA,2BAAA;EACA,uBAAA;ElD+1JP;AkDp3JC;EACE,gBAAA;EACA,2BAAA;ElDs3JH;AkDp3JG;EACE,gBAAA;ElDs3JL;AkDv3JG;EAII,gBAAA;ElDs3JP;AkDn3JK;;EAEE,gBAAA;EACA,2BAAA;ElDq3JP;AkDn3JK;;;EAGE,aAAA;EACA,2BAAA;EACA,uBAAA;ElDq3JP;AkD14JC;EACE,gBAAA;EACA,2BAAA;ElD44JH;AkD14JG;EACE,gBAAA;ElD44JL;AkD74JG;EAII,gBAAA;ElD44JP;AkDz4JK;;EAEE,gBAAA;EACA,2BAAA;ElD24JP;AkDz4JK;;;EAGE,aAAA;EACA,2BAAA;EACA,uBAAA;ElD24JP;AkDh6JC;EACE,gBAAA;EACA,2BAAA;ElDk6JH;AkDh6JG;EACE,gBAAA;ElDk6JL;AkDn6JG;EAII,gBAAA;ElDk6JP;AkD/5JK;;EAEE,gBAAA;EACA,2BAAA;ElDi6JP;AkD/5JK;;;EAGE,aAAA;EACA,2BAAA;EACA,uBAAA;ElDi6JP;AiD7zJD;EACE,eAAA;EACA,oBAAA;EjD+zJD;AiD7zJD;EACE,kBAAA;EACA,kBAAA;EjD+zJD;AmD37JD;EACE,qBAAA;EACA,2BAAA;EACA,+BAAA;EACA,oBAAA;E9C0DA,mDAAA;EACQ,2CAAA;ELo4JT;AmD17JD;EACE,eAAA;EnD47JD;AmDv7JD;EACE,oBAAA;EACA,sCAAA;EvBpBA,8BAAA;EACC,6BAAA;E5B88JF;AmD77JD;EAMI,gBAAA;EnD07JH;AmDr7JD;EACE,eAAA;EACA,kBAAA;EACA,iBAAA;EACA,gBAAA;EnDu7JD;AmD37JD;EAOI,gBAAA;EnDu7JH;AmDl7JD;EACE,oBAAA;EACA,2BAAA;EACA,+BAAA;EvBpCA,iCAAA;EACC,gCAAA;E5By9JF;AmD56JD;;EAGI,kBAAA;EnD66JH;AmDh7JD;;EAMM,qBAAA;EACA,kBAAA;EnD86JL;AmD16JG;;EAEI,eAAA;EvBnEN,8BAAA;EACC,6BAAA;E5Bg/JF;AmDz6JG;;EAEI,kBAAA;EvBlEN,iCAAA;EACC,gCAAA;E5B8+JF;AmDt6JD;EAEI,qBAAA;EnDu6JH;AmDp6JD;EACE,qBAAA;EnDs6JD;AmD95JD;;;EAII,kBAAA;EnD+5JH;AmDn6JD;;;EAOM,oBAAA;EACA,qBAAA;EnDi6JL;AmDz6JD;;EvB/FE,8BAAA;EACC,6BAAA;E5B4gKF;AmD96JD;;;;EAmBQ,6BAAA;EACA,8BAAA;EnDi6JP;AmDr7JD;;;;;;;;EAwBU,6BAAA;EnDu6JT;AmD/7JD;;;;;;;;EA4BU,8BAAA;EnD66JT;AmDz8JD;;EvBvFE,iCAAA;EACC,gCAAA;E5BoiKF;AmD98JD;;;;EAyCQ,gCAAA;EACA,iCAAA;EnD26JP;AmDr9JD;;;;;;;;EA8CU,gCAAA;EnDi7JT;AmD/9JD;;;;;;;;EAkDU,iCAAA;EnDu7JT;AmDz+JD;;;;EA2DI,+BAAA;EnDo7JH;AmD/+JD;;EA+DI,eAAA;EnDo7JH;AmDn/JD;;EAmEI,WAAA;EnDo7JH;AmDv/JD;;;;;;;;;;;;EA0EU,gBAAA;EnD27JT;AmDrgKD;;;;;;;;;;;;EA8EU,iBAAA;EnDq8JT;AmDnhKD;;;;;;;;EAuFU,kBAAA;EnDs8JT;AmD7hKD;;;;;;;;EAgGU,kBAAA;EnDu8JT;AmDviKD;EAsGI,WAAA;EACA,kBAAA;EnDo8JH;AmD17JD;EACE,qBAAA;EnD47JD;AmD77JD;EAKI,kBAAA;EACA,oBAAA;EnD27JH;AmDj8JD;EASM,iBAAA;EnD27JL;AmDp8JD;EAcI,kBAAA;EnDy7JH;AmDv8JD;;EAkBM,+BAAA;EnDy7JL;AmD38JD;EAuBI,eAAA;EnDu7JH;AmD98JD;EAyBM,kCAAA;EnDw7JL;AmDj7JD;EChPE,uBAAA;EpDoqKD;AoDlqKC;EACE,gBAAA;EACA,2BAAA;EACA,uBAAA;EpDoqKH;AoDvqKC;EAMI,2BAAA;EpDoqKL;AoD1qKC;EASI,gBAAA;EACA,2BAAA;EpDoqKL;AoDjqKC;EAEI,8BAAA;EpDkqKL;AmDh8JD;ECnPE,uBAAA;EpDsrKD;AoDprKC;EACE,gBAAA;EACA,2BAAA;EACA,uBAAA;EpDsrKH;AoDzrKC;EAMI,2BAAA;EpDsrKL;AoD5rKC;EASI,gBAAA;EACA,2BAAA;EpDsrKL;AoDnrKC;EAEI,8BAAA;EpDorKL;AmD/8JD;ECtPE,uBAAA;EpDwsKD;AoDtsKC;EACE,gBAAA;EACA,2BAAA;EACA,uBAAA;EpDwsKH;AoD3sKC;EAMI,2BAAA;EpDwsKL;AoD9sKC;EASI,gBAAA;EACA,2BAAA;EpDwsKL;AoDrsKC;EAEI,8BAAA;EpDssKL;AmD99JD;ECzPE,uBAAA;EpD0tKD;AoDxtKC;EACE,gBAAA;EACA,2BAAA;EACA,uBAAA;EpD0tKH;AoD7tKC;EAMI,2BAAA;EpD0tKL;AoDhuKC;EASI,gBAAA;EACA,2BAAA;EpD0tKL;AoDvtKC;EAEI,8BAAA;EpDwtKL;AmD7+JD;EC5PE,uBAAA;EpD4uKD;AoD1uKC;EACE,gBAAA;EACA,2BAAA;EACA,uBAAA;EpD4uKH;AoD/uKC;EAMI,2BAAA;EpD4uKL;AoDlvKC;EASI,gBAAA;EACA,2BAAA;EpD4uKL;AoDzuKC;EAEI,8BAAA;EpD0uKL;AmD5/JD;EC/PE,uBAAA;EpD8vKD;AoD5vKC;EACE,gBAAA;EACA,2BAAA;EACA,uBAAA;EpD8vKH;AoDjwKC;EAMI,2BAAA;EpD8vKL;AoDpwKC;EASI,gBAAA;EACA,2BAAA;EpD8vKL;AoD3vKC;EAEI,8BAAA;EpD4vKL;AqD5wKD;EACE,oBAAA;EACA,gBAAA;EACA,WAAA;EACA,YAAA;EACA,kBAAA;ErD8wKD;AqDnxKD;;;;;EAYI,oBAAA;EACA,QAAA;EACA,SAAA;EACA,WAAA;EACA,cAAA;EACA,aAAA;EACA,WAAA;ErD8wKH;AqD1wKC;EACE,wBAAA;ErD4wKH;AqDxwKC;EACE,qBAAA;ErD0wKH;AsDpyKD;EACE,kBAAA;EACA,eAAA;EACA,qBAAA;EACA,2BAAA;EACA,2BAAA;EACA,oBAAA;EjDwDA,yDAAA;EACQ,iDAAA;EL+uKT;AsD9yKD;EASI,oBAAA;EACA,mCAAA;EtDwyKH;AsDnyKD;EACE,eAAA;EACA,oBAAA;EtDqyKD;AsDnyKD;EACE,cAAA;EACA,oBAAA;EtDqyKD;AuD3zKD;EACE,cAAA;EACA,iBAAA;EACA,mBAAA;EACA,gBAAA;EACA,gBAAA;EACA,8BAAA;EjCRA,cAAA;EAGA,2BAAA;EtBo0KD;AuD5zKC;;EAEE,gBAAA;EACA,uBAAA;EACA,iBAAA;EjCfF,cAAA;EAGA,2BAAA;EtB40KD;AuDzzKC;EACE,YAAA;EACA,iBAAA;EACA,yBAAA;EACA,WAAA;EACA,0BAAA;EvD2zKH;AwD/0KD;EACE,kBAAA;ExDi1KD;AwD70KD;EACE,eAAA;EACA,kBAAA;EACA,iBAAA;EACA,QAAA;EACA,UAAA;EACA,WAAA;EACA,SAAA;EACA,eAAA;EACA,mCAAA;EAIA,YAAA;ExD40KD;AwDz0KC;EnD+GA,uCAAA;EACI,mCAAA;EACC,kCAAA;EACG,+BAAA;EAkER,qDAAA;EAEK,2CAAA;EACG,qCAAA;EL4pKT;AwD/0KC;EnD2GA,oCAAA;EACI,gCAAA;EACC,+BAAA;EACG,4BAAA;ELuuKT;AwDn1KD;EACE,oBAAA;EACA,kBAAA;ExDq1KD;AwDj1KD;EACE,oBAAA;EACA,aAAA;EACA,cAAA;ExDm1KD;AwD/0KD;EACE,oBAAA;EACA,2BAAA;EACA,2BAAA;EACA,sCAAA;EACA,oBAAA;EnDaA,kDAAA;EACQ,0CAAA;EmDZR,sCAAA;UAAA,8BAAA;EAEA,YAAA;ExDi1KD;AwD70KD;EACE,iBAAA;EACA,QAAA;EACA,UAAA;EACA,WAAA;EACA,SAAA;EACA,2BAAA;ExD+0KD;AwD70KC;ElCpEA,YAAA;EAGA,0BAAA;EtBk5KD;AwDh1KC;ElCrEA,cAAA;EAGA,2BAAA;EtBs5KD;AwD/0KD;EACE,eAAA;EACA,kCAAA;EACA,2BAAA;ExDi1KD;AwD90KD;EACE,kBAAA;ExDg1KD;AwD50KD;EACE,WAAA;EACA,yBAAA;ExD80KD;AwDz0KD;EACE,oBAAA;EACA,eAAA;ExD20KD;AwDv0KD;EACE,eAAA;EACA,mBAAA;EACA,+BAAA;ExDy0KD;AwD50KD;EAQI,kBAAA;EACA,kBAAA;ExDu0KH;AwDh1KD;EAaI,mBAAA;ExDs0KH;AwDn1KD;EAiBI,gBAAA;ExDq0KH;AwDh0KD;EACE,oBAAA;EACA,cAAA;EACA,aAAA;EACA,cAAA;EACA,kBAAA;ExDk0KD;AwDhzKD;EAZE;IACE,cAAA;IACA,mBAAA;IxD+zKD;EwD7zKD;InDtEA,mDAAA;IACQ,2CAAA;ILs4KP;EwD5zKD;IAAY,cAAA;IxD+zKX;EACF;AwD1zKD;EAFE;IAAY,cAAA;IxDg0KX;EACF;AyD98KD;EACE,oBAAA;EACA,eAAA;EACA,gBAAA;EACA,qBAAA;EACA,iBAAA;EACA,kBAAA;EnCTA,YAAA;EAGA,0BAAA;EtBw9KD;AyD/8KC;EnCZA,cAAA;EAGA,2BAAA;EtB49KD;AyDl9KC;EAAW,kBAAA;EAAmB,gBAAA;EzDs9K/B;AyDr9KC;EAAW,kBAAA;EAAmB,gBAAA;EzDy9K/B;AyDx9KC;EAAW,iBAAA;EAAmB,gBAAA;EzD49K/B;AyD39KC;EAAW,mBAAA;EAAmB,gBAAA;EzD+9K/B;AyD39KD;EACE,kBAAA;EACA,kBAAA;EACA,gBAAA;EACA,oBAAA;EACA,uBAAA;EACA,2BAAA;EACA,oBAAA;EzD69KD;AyDz9KD;EACE,oBAAA;EACA,UAAA;EACA,WAAA;EACA,2BAAA;EACA,qBAAA;EzD29KD;AyDx9KC;EACE,WAAA;EACA,WAAA;EACA,mBAAA;EACA,yBAAA;EACA,2BAAA;EzD09KH;AyDx9KC;EACE,WAAA;EACA,WAAA;EACA,yBAAA;EACA,2BAAA;EzD09KH;AyDx9KC;EACE,WAAA;EACA,YAAA;EACA,yBAAA;EACA,2BAAA;EzD09KH;AyDx9KC;EACE,UAAA;EACA,SAAA;EACA,kBAAA;EACA,6BAAA;EACA,6BAAA;EzD09KH;AyDx9KC;EACE,UAAA;EACA,UAAA;EACA,kBAAA;EACA,6BAAA;EACA,4BAAA;EzD09KH;AyDx9KC;EACE,QAAA;EACA,WAAA;EACA,mBAAA;EACA,yBAAA;EACA,8BAAA;EzD09KH;AyDx9KC;EACE,QAAA;EACA,WAAA;EACA,yBAAA;EACA,8BAAA;EzD09KH;AyDx9KC;EACE,QAAA;EACA,YAAA;EACA,yBAAA;EACA,8BAAA;EzD09KH;A0DjjLD;EACE,oBAAA;EACA,QAAA;EACA,SAAA;EACA,eAAA;EACA,eAAA;EACA,kBAAA;EACA,cAAA;EAEA,iBAAA;EACA,qBAAA;EACA,yBAAA;EACA,kBAAA;EACA,2BAAA;EACA,sCAAA;UAAA,8BAAA;EACA,2BAAA;EACA,sCAAA;EACA,oBAAA;ErD8CA,mDAAA;EACQ,2CAAA;EqD3CR,qBAAA;E1DijLD;A0D9iLC;EAAY,mBAAA;E1DijLb;A0DhjLC;EAAY,mBAAA;E1DmjLb;A0DljLC;EAAY,kBAAA;E1DqjLb;A0DpjLC;EAAY,oBAAA;E1DujLb;A0DpjLD;EACE,WAAA;EACA,mBAAA;EACA,iBAAA;EACA,2BAAA;EACA,kCAAA;EACA,4BAAA;E1DsjLD;A0DnjLD;EACE,mBAAA;E1DqjLD;A0D7iLC;;EAEE,oBAAA;EACA,gBAAA;EACA,UAAA;EACA,WAAA;EACA,2BAAA;EACA,qBAAA;E1D+iLH;A0D5iLD;EACE,oBAAA;E1D8iLD;A0D5iLD;EACE,oBAAA;EACA,aAAA;E1D8iLD;A0D1iLC;EACE,WAAA;EACA,oBAAA;EACA,wBAAA;EACA,2BAAA;EACA,uCAAA;EACA,eAAA;E1D4iLH;A0D3iLG;EACE,cAAA;EACA,aAAA;EACA,oBAAA;EACA,wBAAA;EACA,2BAAA;E1D6iLL;A0D1iLC;EACE,UAAA;EACA,aAAA;EACA,mBAAA;EACA,sBAAA;EACA,6BAAA;EACA,yCAAA;E1D4iLH;A0D3iLG;EACE,cAAA;EACA,WAAA;EACA,eAAA;EACA,sBAAA;EACA,6BAAA;E1D6iLL;A0D1iLC;EACE,WAAA;EACA,oBAAA;EACA,qBAAA;EACA,8BAAA;EACA,0CAAA;EACA,YAAA;E1D4iLH;A0D3iLG;EACE,cAAA;EACA,UAAA;EACA,oBAAA;EACA,qBAAA;EACA,8BAAA;E1D6iLL;A0DziLC;EACE,UAAA;EACA,cAAA;EACA,mBAAA;EACA,uBAAA;EACA,4BAAA;EACA,wCAAA;E1D2iLH;A0D1iLG;EACE,cAAA;EACA,YAAA;EACA,uBAAA;EACA,4BAAA;EACA,eAAA;E1D4iLL;A2DxqLD;EACE,oBAAA;E3D0qLD;A2DvqLD;EACE,oBAAA;EACA,kBAAA;EACA,aAAA;E3DyqLD;A2D5qLD;EAMI,eAAA;EACA,oBAAA;EtD6KF,2CAAA;EACK,sCAAA;EACG,mCAAA;EL6/KT;A2DnrLD;;EAcM,gBAAA;E3DyqLL;A2D/oLC;EAAA;IArBI,wDAAA;SAAA,8CAAA;YAAA,wCAAA;IACA,qCAAA;YAAA,6BAAA;IACA,2BAAA;YAAA,mBAAA;I3DwqLH;E2DtqLG;;IAEE,4CAAA;YAAA,oCAAA;IACA,SAAA;I3DwqLL;E2DtqLG;;IAEE,6CAAA;YAAA,qCAAA;IACA,SAAA;I3DwqLL;E2DtqLG;;;IAGE,yCAAA;YAAA,iCAAA;IACA,SAAA;I3DwqLL;EACF;A2D9sLD;;;EA6CI,gBAAA;E3DsqLH;A2DntLD;EAiDI,SAAA;E3DqqLH;A2DttLD;;EAsDI,oBAAA;EACA,QAAA;EACA,aAAA;E3DoqLH;A2D5tLD;EA4DI,YAAA;E3DmqLH;A2D/tLD;EA+DI,aAAA;E3DmqLH;A2DluLD;;EAmEI,SAAA;E3DmqLH;A2DtuLD;EAuEI,aAAA;E3DkqLH;A2DzuLD;EA0EI,YAAA;E3DkqLH;A2D1pLD;EACE,oBAAA;EACA,QAAA;EACA,SAAA;EACA,WAAA;EACA,YAAA;ErC9FA,cAAA;EAGA,2BAAA;EqC6FA,iBAAA;EACA,gBAAA;EACA,oBAAA;EACA,2CAAA;E3D6pLD;A2DxpLC;EblGE,oGAAA;EACA,+FAAA;EACA,sHAAA;EAAA,gGAAA;EACA,6BAAA;EACA,wHAAA;E9C6vLH;A2D5pLC;EACE,YAAA;EACA,UAAA;EbvGA,oGAAA;EACA,+FAAA;EACA,sHAAA;EAAA,gGAAA;EACA,6BAAA;EACA,wHAAA;E9CswLH;A2D9pLC;;EAEE,YAAA;EACA,gBAAA;EACA,uBAAA;ErCtHF,cAAA;EAGA,2BAAA;EtBqxLD;A2D/rLD;;;;EAsCI,oBAAA;EACA,UAAA;EACA,YAAA;EACA,uBAAA;E3D+pLH;A2DxsLD;;EA6CI,WAAA;EACA,oBAAA;E3D+pLH;A2D7sLD;;EAkDI,YAAA;EACA,qBAAA;E3D+pLH;A2DltLD;;EAuDI,aAAA;EACA,cAAA;EACA,mBAAA;EACA,oBAAA;E3D+pLH;A2D1pLG;EACE,kBAAA;E3D4pLL;A2DxpLG;EACE,kBAAA;E3D0pLL;A2DhpLD;EACE,oBAAA;EACA,cAAA;EACA,WAAA;EACA,aAAA;EACA,YAAA;EACA,mBAAA;EACA,iBAAA;EACA,kBAAA;EACA,oBAAA;E3DkpLD;A2D3pLD;EAYI,uBAAA;EACA,aAAA;EACA,cAAA;EACA,aAAA;EACA,qBAAA;EACA,2BAAA;EACA,qBAAA;EACA,iBAAA;EAUA,2BAAA;EACA,oCAAA;E3DyoLH;A2DvqLD;EAiCI,WAAA;EACA,aAAA;EACA,cAAA;EACA,2BAAA;E3DyoLH;A2DloLD;EACE,oBAAA;EACA,WAAA;EACA,YAAA;EACA,cAAA;EACA,aAAA;EACA,mBAAA;EACA,sBAAA;EACA,gBAAA;EACA,oBAAA;EACA,2CAAA;E3DooLD;A2DnoLC;EACE,mBAAA;E3DqoLH;A2D5lLD;EAhCE;;;;IAKI,aAAA;IACA,cAAA;IACA,mBAAA;IACA,iBAAA;I3D8nLH;E2DtoLD;;IAYI,oBAAA;I3D8nLH;E2D1oLD;;IAgBI,qBAAA;I3D8nLH;E2DznLD;IACE,WAAA;IACA,YAAA;IACA,sBAAA;I3D2nLD;E2DvnLD;IACE,cAAA;I3DynLD;EACF;A4Dr3LC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAEE,cAAA;EACA,gBAAA;E5Dm5LH;A4Dj5LC;;;;;;;;;;;;;;;EACE,aAAA;E5Di6LH;AiCz6LD;E4BRE,gBAAA;EACA,mBAAA;EACA,oBAAA;E7Do7LD;AiC36LD;EACE,yBAAA;EjC66LD;AiC36LD;EACE,wBAAA;EjC66LD;AiCr6LD;EACE,0BAAA;EjCu6LD;AiCr6LD;EACE,2BAAA;EjCu6LD;AiCr6LD;EACE,oBAAA;EjCu6LD;AiCr6LD;E6BzBE,aAAA;EACA,oBAAA;EACA,mBAAA;EACA,+BAAA;EACA,WAAA;E9Di8LD;AiCn6LD;EACE,0BAAA;EACA,+BAAA;EjCq6LD;AiC95LD;EACE,iBAAA;EjCg6LD;A+Dl8LD;EACE,qBAAA;E/Do8LD;A+D97LD;;;;ECdE,0BAAA;EhEk9LD;A+D77LD;;;;;;;;;;;;EAYE,0BAAA;E/D+7LD;A+Dx7LD;EAAA;IChDE,2BAAA;IhE4+LC;EgE3+LD;IAAU,gBAAA;IhE8+LT;EgE7+LD;IAAU,+BAAA;IhEg/LT;EgE/+LD;;IACU,gCAAA;IhEk/LT;EACF;A+Dl8LD;EAAA;IAFI,2BAAA;I/Dw8LD;EACF;A+Dl8LD;EAAA;IAFI,4BAAA;I/Dw8LD;EACF;A+Dl8LD;EAAA;IAFI,kCAAA;I/Dw8LD;EACF;A+Dj8LD;EAAA;ICrEE,2BAAA;IhE0gMC;EgEzgMD;IAAU,gBAAA;IhE4gMT;EgE3gMD;IAAU,+BAAA;IhE8gMT;EgE7gMD;;IACU,gCAAA;IhEghMT;EACF;A+D38LD;EAAA;IAFI,2BAAA;I/Di9LD;EACF;A+D38LD;EAAA;IAFI,4BAAA;I/Di9LD;EACF;A+D38LD;EAAA;IAFI,kCAAA;I/Di9LD;EACF;A+D18LD;EAAA;IC1FE,2BAAA;IhEwiMC;EgEviMD;IAAU,gBAAA;IhE0iMT;EgEziMD;IAAU,+BAAA;IhE4iMT;EgE3iMD;;IACU,gCAAA;IhE8iMT;EACF;A+Dp9LD;EAAA;IAFI,2BAAA;I/D09LD;EACF;A+Dp9LD;EAAA;IAFI,4BAAA;I/D09LD;EACF;A+Dp9LD;EAAA;IAFI,kCAAA;I/D09LD;EACF;A+Dn9LD;EAAA;IC/GE,2BAAA;IhEskMC;EgErkMD;IAAU,gBAAA;IhEwkMT;EgEvkMD;IAAU,+BAAA;IhE0kMT;EgEzkMD;;IACU,gCAAA;IhE4kMT;EACF;A+D79LD;EAAA;IAFI,2BAAA;I/Dm+LD;EACF;A+D79LD;EAAA;IAFI,4BAAA;I/Dm+LD;EACF;A+D79LD;EAAA;IAFI,kCAAA;I/Dm+LD;EACF;A+D59LD;EAAA;IC5HE,0BAAA;IhE4lMC;EACF;A+D59LD;EAAA;ICjIE,0BAAA;IhEimMC;EACF;A+D59LD;EAAA;ICtIE,0BAAA;IhEsmMC;EACF;A+D59LD;EAAA;IC3IE,0BAAA;IhE2mMC;EACF;A+Dz9LD;ECnJE,0BAAA;EhE+mMD;A+Dt9LD;EAAA;ICjKE,2BAAA;IhE2nMC;EgE1nMD;IAAU,gBAAA;IhE6nMT;EgE5nMD;IAAU,+BAAA;IhE+nMT;EgE9nMD;;IACU,gCAAA;IhEioMT;EACF;A+Dp+LD;EACE,0BAAA;E/Ds+LD;A+Dj+LD;EAAA;IAFI,2BAAA;I/Du+LD;EACF;A+Dr+LD;EACE,0BAAA;E/Du+LD;A+Dl+LD;EAAA;IAFI,4BAAA;I/Dw+LD;EACF;A+Dt+LD;EACE,0BAAA;E/Dw+LD;A+Dn+LD;EAAA;IAFI,kCAAA;I/Dy+LD;EACF;A+Dl+LD;EAAA;ICpLE,0BAAA;IhE0pMC;EACF","file":"bootstrap.css","sourcesContent":["/*! normalize.css v3.0.2 | MIT License | git.io/normalize */\nhtml {\n font-family: sans-serif;\n -ms-text-size-adjust: 100%;\n -webkit-text-size-adjust: 100%;\n}\nbody {\n margin: 0;\n}\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n display: block;\n}\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block;\n vertical-align: baseline;\n}\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n[hidden],\ntemplate {\n display: none;\n}\na {\n background-color: transparent;\n}\na:active,\na:hover {\n outline: 0;\n}\nabbr[title] {\n border-bottom: 1px dotted;\n}\nb,\nstrong {\n font-weight: bold;\n}\ndfn {\n font-style: italic;\n}\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\nmark {\n background: #ff0;\n color: #000;\n}\nsmall {\n font-size: 80%;\n}\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\nsup {\n top: -0.5em;\n}\nsub {\n bottom: -0.25em;\n}\nimg {\n border: 0;\n}\nsvg:not(:root) {\n overflow: hidden;\n}\nfigure {\n margin: 1em 40px;\n}\nhr {\n -moz-box-sizing: content-box;\n box-sizing: content-box;\n height: 0;\n}\npre {\n overflow: auto;\n}\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n color: inherit;\n font: inherit;\n margin: 0;\n}\nbutton {\n overflow: visible;\n}\nbutton,\nselect {\n text-transform: none;\n}\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button;\n cursor: pointer;\n}\nbutton[disabled],\nhtml input[disabled] {\n cursor: default;\n}\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0;\n}\ninput {\n line-height: normal;\n}\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n box-sizing: border-box;\n padding: 0;\n}\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\ninput[type=\"search\"] {\n -webkit-appearance: textfield;\n -moz-box-sizing: content-box;\n -webkit-box-sizing: content-box;\n box-sizing: content-box;\n}\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: 0.35em 0.625em 0.75em;\n}\nlegend {\n border: 0;\n padding: 0;\n}\ntextarea {\n overflow: auto;\n}\noptgroup {\n font-weight: bold;\n}\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n}\ntd,\nth {\n padding: 0;\n}\n/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n@media print {\n *,\n *:before,\n *:after {\n background: transparent !important;\n color: #000 !important;\n box-shadow: none !important;\n text-shadow: none !important;\n }\n a,\n a:visited {\n text-decoration: underline;\n }\n a[href]:after {\n content: \" (\" attr(href) \")\";\n }\n abbr[title]:after {\n content: \" (\" attr(title) \")\";\n }\n a[href^=\"#\"]:after,\n a[href^=\"javascript:\"]:after {\n content: \"\";\n }\n pre,\n blockquote {\n border: 1px solid #999;\n page-break-inside: avoid;\n }\n thead {\n display: table-header-group;\n }\n tr,\n img {\n page-break-inside: avoid;\n }\n img {\n max-width: 100% !important;\n }\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n h2,\n h3 {\n page-break-after: avoid;\n }\n select {\n background: #fff !important;\n }\n .navbar {\n display: none;\n }\n .btn > .caret,\n .dropup > .btn > .caret {\n border-top-color: #000 !important;\n }\n .label {\n border: 1px solid #000;\n }\n .table {\n border-collapse: collapse !important;\n }\n .table td,\n .table th {\n background-color: #fff !important;\n }\n .table-bordered th,\n .table-bordered td {\n border: 1px solid #ddd !important;\n }\n}\n@font-face {\n font-family: 'Glyphicons Halflings';\n src: url('../fonts/glyphicons-halflings-regular.eot');\n src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');\n}\n.glyphicon {\n position: relative;\n top: 1px;\n display: inline-block;\n font-family: 'Glyphicons Halflings';\n font-style: normal;\n font-weight: normal;\n line-height: 1;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n.glyphicon-asterisk:before {\n content: \"\\2a\";\n}\n.glyphicon-plus:before {\n content: \"\\2b\";\n}\n.glyphicon-euro:before,\n.glyphicon-eur:before {\n content: \"\\20ac\";\n}\n.glyphicon-minus:before {\n content: \"\\2212\";\n}\n.glyphicon-cloud:before {\n content: \"\\2601\";\n}\n.glyphicon-envelope:before {\n content: \"\\2709\";\n}\n.glyphicon-pencil:before {\n content: \"\\270f\";\n}\n.glyphicon-glass:before {\n content: \"\\e001\";\n}\n.glyphicon-music:before {\n content: \"\\e002\";\n}\n.glyphicon-search:before {\n content: \"\\e003\";\n}\n.glyphicon-heart:before {\n content: \"\\e005\";\n}\n.glyphicon-star:before {\n content: \"\\e006\";\n}\n.glyphicon-star-empty:before {\n content: \"\\e007\";\n}\n.glyphicon-user:before {\n content: \"\\e008\";\n}\n.glyphicon-film:before {\n content: \"\\e009\";\n}\n.glyphicon-th-large:before {\n content: \"\\e010\";\n}\n.glyphicon-th:before {\n content: \"\\e011\";\n}\n.glyphicon-th-list:before {\n content: \"\\e012\";\n}\n.glyphicon-ok:before {\n content: \"\\e013\";\n}\n.glyphicon-remove:before {\n content: \"\\e014\";\n}\n.glyphicon-zoom-in:before {\n content: \"\\e015\";\n}\n.glyphicon-zoom-out:before {\n content: \"\\e016\";\n}\n.glyphicon-off:before {\n content: \"\\e017\";\n}\n.glyphicon-signal:before {\n content: \"\\e018\";\n}\n.glyphicon-cog:before {\n content: \"\\e019\";\n}\n.glyphicon-trash:before {\n content: \"\\e020\";\n}\n.glyphicon-home:before {\n content: \"\\e021\";\n}\n.glyphicon-file:before {\n content: \"\\e022\";\n}\n.glyphicon-time:before {\n content: \"\\e023\";\n}\n.glyphicon-road:before {\n content: \"\\e024\";\n}\n.glyphicon-download-alt:before {\n content: \"\\e025\";\n}\n.glyphicon-download:before {\n content: \"\\e026\";\n}\n.glyphicon-upload:before {\n content: \"\\e027\";\n}\n.glyphicon-inbox:before {\n content: \"\\e028\";\n}\n.glyphicon-play-circle:before {\n content: \"\\e029\";\n}\n.glyphicon-repeat:before {\n content: \"\\e030\";\n}\n.glyphicon-refresh:before {\n content: \"\\e031\";\n}\n.glyphicon-list-alt:before {\n content: \"\\e032\";\n}\n.glyphicon-lock:before {\n content: \"\\e033\";\n}\n.glyphicon-flag:before {\n content: \"\\e034\";\n}\n.glyphicon-headphones:before {\n content: \"\\e035\";\n}\n.glyphicon-volume-off:before {\n content: \"\\e036\";\n}\n.glyphicon-volume-down:before {\n content: \"\\e037\";\n}\n.glyphicon-volume-up:before {\n content: \"\\e038\";\n}\n.glyphicon-qrcode:before {\n content: \"\\e039\";\n}\n.glyphicon-barcode:before {\n content: \"\\e040\";\n}\n.glyphicon-tag:before {\n content: \"\\e041\";\n}\n.glyphicon-tags:before {\n content: \"\\e042\";\n}\n.glyphicon-book:before {\n content: \"\\e043\";\n}\n.glyphicon-bookmark:before {\n content: \"\\e044\";\n}\n.glyphicon-print:before {\n content: \"\\e045\";\n}\n.glyphicon-camera:before {\n content: \"\\e046\";\n}\n.glyphicon-font:before {\n content: \"\\e047\";\n}\n.glyphicon-bold:before {\n content: \"\\e048\";\n}\n.glyphicon-italic:before {\n content: \"\\e049\";\n}\n.glyphicon-text-height:before {\n content: \"\\e050\";\n}\n.glyphicon-text-width:before {\n content: \"\\e051\";\n}\n.glyphicon-align-left:before {\n content: \"\\e052\";\n}\n.glyphicon-align-center:before {\n content: \"\\e053\";\n}\n.glyphicon-align-right:before {\n content: \"\\e054\";\n}\n.glyphicon-align-justify:before {\n content: \"\\e055\";\n}\n.glyphicon-list:before {\n content: \"\\e056\";\n}\n.glyphicon-indent-left:before {\n content: \"\\e057\";\n}\n.glyphicon-indent-right:before {\n content: \"\\e058\";\n}\n.glyphicon-facetime-video:before {\n content: \"\\e059\";\n}\n.glyphicon-picture:before {\n content: \"\\e060\";\n}\n.glyphicon-map-marker:before {\n content: \"\\e062\";\n}\n.glyphicon-adjust:before {\n content: \"\\e063\";\n}\n.glyphicon-tint:before {\n content: \"\\e064\";\n}\n.glyphicon-edit:before {\n content: \"\\e065\";\n}\n.glyphicon-share:before {\n content: \"\\e066\";\n}\n.glyphicon-check:before {\n content: \"\\e067\";\n}\n.glyphicon-move:before {\n content: \"\\e068\";\n}\n.glyphicon-step-backward:before {\n content: \"\\e069\";\n}\n.glyphicon-fast-backward:before {\n content: \"\\e070\";\n}\n.glyphicon-backward:before {\n content: \"\\e071\";\n}\n.glyphicon-play:before {\n content: \"\\e072\";\n}\n.glyphicon-pause:before {\n content: \"\\e073\";\n}\n.glyphicon-stop:before {\n content: \"\\e074\";\n}\n.glyphicon-forward:before {\n content: \"\\e075\";\n}\n.glyphicon-fast-forward:before {\n content: \"\\e076\";\n}\n.glyphicon-step-forward:before {\n content: \"\\e077\";\n}\n.glyphicon-eject:before {\n content: \"\\e078\";\n}\n.glyphicon-chevron-left:before {\n content: \"\\e079\";\n}\n.glyphicon-chevron-right:before {\n content: \"\\e080\";\n}\n.glyphicon-plus-sign:before {\n content: \"\\e081\";\n}\n.glyphicon-minus-sign:before {\n content: \"\\e082\";\n}\n.glyphicon-remove-sign:before {\n content: \"\\e083\";\n}\n.glyphicon-ok-sign:before {\n content: \"\\e084\";\n}\n.glyphicon-question-sign:before {\n content: \"\\e085\";\n}\n.glyphicon-info-sign:before {\n content: \"\\e086\";\n}\n.glyphicon-screenshot:before {\n content: \"\\e087\";\n}\n.glyphicon-remove-circle:before {\n content: \"\\e088\";\n}\n.glyphicon-ok-circle:before {\n content: \"\\e089\";\n}\n.glyphicon-ban-circle:before {\n content: \"\\e090\";\n}\n.glyphicon-arrow-left:before {\n content: \"\\e091\";\n}\n.glyphicon-arrow-right:before {\n content: \"\\e092\";\n}\n.glyphicon-arrow-up:before {\n content: \"\\e093\";\n}\n.glyphicon-arrow-down:before {\n content: \"\\e094\";\n}\n.glyphicon-share-alt:before {\n content: \"\\e095\";\n}\n.glyphicon-resize-full:before {\n content: \"\\e096\";\n}\n.glyphicon-resize-small:before {\n content: \"\\e097\";\n}\n.glyphicon-exclamation-sign:before {\n content: \"\\e101\";\n}\n.glyphicon-gift:before {\n content: \"\\e102\";\n}\n.glyphicon-leaf:before {\n content: \"\\e103\";\n}\n.glyphicon-fire:before {\n content: \"\\e104\";\n}\n.glyphicon-eye-open:before {\n content: \"\\e105\";\n}\n.glyphicon-eye-close:before {\n content: \"\\e106\";\n}\n.glyphicon-warning-sign:before {\n content: \"\\e107\";\n}\n.glyphicon-plane:before {\n content: \"\\e108\";\n}\n.glyphicon-calendar:before {\n content: \"\\e109\";\n}\n.glyphicon-random:before {\n content: \"\\e110\";\n}\n.glyphicon-comment:before {\n content: \"\\e111\";\n}\n.glyphicon-magnet:before {\n content: \"\\e112\";\n}\n.glyphicon-chevron-up:before {\n content: \"\\e113\";\n}\n.glyphicon-chevron-down:before {\n content: \"\\e114\";\n}\n.glyphicon-retweet:before {\n content: \"\\e115\";\n}\n.glyphicon-shopping-cart:before {\n content: \"\\e116\";\n}\n.glyphicon-folder-close:before {\n content: \"\\e117\";\n}\n.glyphicon-folder-open:before {\n content: \"\\e118\";\n}\n.glyphicon-resize-vertical:before {\n content: \"\\e119\";\n}\n.glyphicon-resize-horizontal:before {\n content: \"\\e120\";\n}\n.glyphicon-hdd:before {\n content: \"\\e121\";\n}\n.glyphicon-bullhorn:before {\n content: \"\\e122\";\n}\n.glyphicon-bell:before {\n content: \"\\e123\";\n}\n.glyphicon-certificate:before {\n content: \"\\e124\";\n}\n.glyphicon-thumbs-up:before {\n content: \"\\e125\";\n}\n.glyphicon-thumbs-down:before {\n content: \"\\e126\";\n}\n.glyphicon-hand-right:before {\n content: \"\\e127\";\n}\n.glyphicon-hand-left:before {\n content: \"\\e128\";\n}\n.glyphicon-hand-up:before {\n content: \"\\e129\";\n}\n.glyphicon-hand-down:before {\n content: \"\\e130\";\n}\n.glyphicon-circle-arrow-right:before {\n content: \"\\e131\";\n}\n.glyphicon-circle-arrow-left:before {\n content: \"\\e132\";\n}\n.glyphicon-circle-arrow-up:before {\n content: \"\\e133\";\n}\n.glyphicon-circle-arrow-down:before {\n content: \"\\e134\";\n}\n.glyphicon-globe:before {\n content: \"\\e135\";\n}\n.glyphicon-wrench:before {\n content: \"\\e136\";\n}\n.glyphicon-tasks:before {\n content: \"\\e137\";\n}\n.glyphicon-filter:before {\n content: \"\\e138\";\n}\n.glyphicon-briefcase:before {\n content: \"\\e139\";\n}\n.glyphicon-fullscreen:before {\n content: \"\\e140\";\n}\n.glyphicon-dashboard:before {\n content: \"\\e141\";\n}\n.glyphicon-paperclip:before {\n content: \"\\e142\";\n}\n.glyphicon-heart-empty:before {\n content: \"\\e143\";\n}\n.glyphicon-link:before {\n content: \"\\e144\";\n}\n.glyphicon-phone:before {\n content: \"\\e145\";\n}\n.glyphicon-pushpin:before {\n content: \"\\e146\";\n}\n.glyphicon-usd:before {\n content: \"\\e148\";\n}\n.glyphicon-gbp:before {\n content: \"\\e149\";\n}\n.glyphicon-sort:before {\n content: \"\\e150\";\n}\n.glyphicon-sort-by-alphabet:before {\n content: \"\\e151\";\n}\n.glyphicon-sort-by-alphabet-alt:before {\n content: \"\\e152\";\n}\n.glyphicon-sort-by-order:before {\n content: \"\\e153\";\n}\n.glyphicon-sort-by-order-alt:before {\n content: \"\\e154\";\n}\n.glyphicon-sort-by-attributes:before {\n content: \"\\e155\";\n}\n.glyphicon-sort-by-attributes-alt:before {\n content: \"\\e156\";\n}\n.glyphicon-unchecked:before {\n content: \"\\e157\";\n}\n.glyphicon-expand:before {\n content: \"\\e158\";\n}\n.glyphicon-collapse-down:before {\n content: \"\\e159\";\n}\n.glyphicon-collapse-up:before {\n content: \"\\e160\";\n}\n.glyphicon-log-in:before {\n content: \"\\e161\";\n}\n.glyphicon-flash:before {\n content: \"\\e162\";\n}\n.glyphicon-log-out:before {\n content: \"\\e163\";\n}\n.glyphicon-new-window:before {\n content: \"\\e164\";\n}\n.glyphicon-record:before {\n content: \"\\e165\";\n}\n.glyphicon-save:before {\n content: \"\\e166\";\n}\n.glyphicon-open:before {\n content: \"\\e167\";\n}\n.glyphicon-saved:before {\n content: \"\\e168\";\n}\n.glyphicon-import:before {\n content: \"\\e169\";\n}\n.glyphicon-export:before {\n content: \"\\e170\";\n}\n.glyphicon-send:before {\n content: \"\\e171\";\n}\n.glyphicon-floppy-disk:before {\n content: \"\\e172\";\n}\n.glyphicon-floppy-saved:before {\n content: \"\\e173\";\n}\n.glyphicon-floppy-remove:before {\n content: \"\\e174\";\n}\n.glyphicon-floppy-save:before {\n content: \"\\e175\";\n}\n.glyphicon-floppy-open:before {\n content: \"\\e176\";\n}\n.glyphicon-credit-card:before {\n content: \"\\e177\";\n}\n.glyphicon-transfer:before {\n content: \"\\e178\";\n}\n.glyphicon-cutlery:before {\n content: \"\\e179\";\n}\n.glyphicon-header:before {\n content: \"\\e180\";\n}\n.glyphicon-compressed:before {\n content: \"\\e181\";\n}\n.glyphicon-earphone:before {\n content: \"\\e182\";\n}\n.glyphicon-phone-alt:before {\n content: \"\\e183\";\n}\n.glyphicon-tower:before {\n content: \"\\e184\";\n}\n.glyphicon-stats:before {\n content: \"\\e185\";\n}\n.glyphicon-sd-video:before {\n content: \"\\e186\";\n}\n.glyphicon-hd-video:before {\n content: \"\\e187\";\n}\n.glyphicon-subtitles:before {\n content: \"\\e188\";\n}\n.glyphicon-sound-stereo:before {\n content: \"\\e189\";\n}\n.glyphicon-sound-dolby:before {\n content: \"\\e190\";\n}\n.glyphicon-sound-5-1:before {\n content: \"\\e191\";\n}\n.glyphicon-sound-6-1:before {\n content: \"\\e192\";\n}\n.glyphicon-sound-7-1:before {\n content: \"\\e193\";\n}\n.glyphicon-copyright-mark:before {\n content: \"\\e194\";\n}\n.glyphicon-registration-mark:before {\n content: \"\\e195\";\n}\n.glyphicon-cloud-download:before {\n content: \"\\e197\";\n}\n.glyphicon-cloud-upload:before {\n content: \"\\e198\";\n}\n.glyphicon-tree-conifer:before {\n content: \"\\e199\";\n}\n.glyphicon-tree-deciduous:before {\n content: \"\\e200\";\n}\n* {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n*:before,\n*:after {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\nhtml {\n font-size: 10px;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\nbody {\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-size: 14px;\n line-height: 1.42857143;\n color: #333333;\n background-color: #ffffff;\n}\ninput,\nbutton,\nselect,\ntextarea {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\na {\n color: #428bca;\n text-decoration: none;\n}\na:hover,\na:focus {\n color: #2a6496;\n text-decoration: underline;\n}\na:focus {\n outline: thin dotted;\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\nfigure {\n margin: 0;\n}\nimg {\n vertical-align: middle;\n}\n.img-responsive,\n.thumbnail > img,\n.thumbnail a > img,\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n display: block;\n max-width: 100%;\n height: auto;\n}\n.img-rounded {\n border-radius: 6px;\n}\n.img-thumbnail {\n padding: 4px;\n line-height: 1.42857143;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n border-radius: 4px;\n -webkit-transition: all 0.2s ease-in-out;\n -o-transition: all 0.2s ease-in-out;\n transition: all 0.2s ease-in-out;\n display: inline-block;\n max-width: 100%;\n height: auto;\n}\n.img-circle {\n border-radius: 50%;\n}\nhr {\n margin-top: 20px;\n margin-bottom: 20px;\n border: 0;\n border-top: 1px solid #eeeeee;\n}\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n border: 0;\n}\n.sr-only-focusable:active,\n.sr-only-focusable:focus {\n position: static;\n width: auto;\n height: auto;\n margin: 0;\n overflow: visible;\n clip: auto;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n font-family: inherit;\n font-weight: 500;\n line-height: 1.1;\n color: inherit;\n}\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small,\n.h1 small,\n.h2 small,\n.h3 small,\n.h4 small,\n.h5 small,\n.h6 small,\nh1 .small,\nh2 .small,\nh3 .small,\nh4 .small,\nh5 .small,\nh6 .small,\n.h1 .small,\n.h2 .small,\n.h3 .small,\n.h4 .small,\n.h5 .small,\n.h6 .small {\n font-weight: normal;\n line-height: 1;\n color: #777777;\n}\nh1,\n.h1,\nh2,\n.h2,\nh3,\n.h3 {\n margin-top: 20px;\n margin-bottom: 10px;\n}\nh1 small,\n.h1 small,\nh2 small,\n.h2 small,\nh3 small,\n.h3 small,\nh1 .small,\n.h1 .small,\nh2 .small,\n.h2 .small,\nh3 .small,\n.h3 .small {\n font-size: 65%;\n}\nh4,\n.h4,\nh5,\n.h5,\nh6,\n.h6 {\n margin-top: 10px;\n margin-bottom: 10px;\n}\nh4 small,\n.h4 small,\nh5 small,\n.h5 small,\nh6 small,\n.h6 small,\nh4 .small,\n.h4 .small,\nh5 .small,\n.h5 .small,\nh6 .small,\n.h6 .small {\n font-size: 75%;\n}\nh1,\n.h1 {\n font-size: 36px;\n}\nh2,\n.h2 {\n font-size: 30px;\n}\nh3,\n.h3 {\n font-size: 24px;\n}\nh4,\n.h4 {\n font-size: 18px;\n}\nh5,\n.h5 {\n font-size: 14px;\n}\nh6,\n.h6 {\n font-size: 12px;\n}\np {\n margin: 0 0 10px;\n}\n.lead {\n margin-bottom: 20px;\n font-size: 16px;\n font-weight: 300;\n line-height: 1.4;\n}\n@media (min-width: 768px) {\n .lead {\n font-size: 21px;\n }\n}\nsmall,\n.small {\n font-size: 85%;\n}\nmark,\n.mark {\n background-color: #fcf8e3;\n padding: .2em;\n}\n.text-left {\n text-align: left;\n}\n.text-right {\n text-align: right;\n}\n.text-center {\n text-align: center;\n}\n.text-justify {\n text-align: justify;\n}\n.text-nowrap {\n white-space: nowrap;\n}\n.text-lowercase {\n text-transform: lowercase;\n}\n.text-uppercase {\n text-transform: uppercase;\n}\n.text-capitalize {\n text-transform: capitalize;\n}\n.text-muted {\n color: #777777;\n}\n.text-primary {\n color: #428bca;\n}\na.text-primary:hover {\n color: #3071a9;\n}\n.text-success {\n color: #3c763d;\n}\na.text-success:hover {\n color: #2b542c;\n}\n.text-info {\n color: #31708f;\n}\na.text-info:hover {\n color: #245269;\n}\n.text-warning {\n color: #8a6d3b;\n}\na.text-warning:hover {\n color: #66512c;\n}\n.text-danger {\n color: #a94442;\n}\na.text-danger:hover {\n color: #843534;\n}\n.bg-primary {\n color: #fff;\n background-color: #428bca;\n}\na.bg-primary:hover {\n background-color: #3071a9;\n}\n.bg-success {\n background-color: #dff0d8;\n}\na.bg-success:hover {\n background-color: #c1e2b3;\n}\n.bg-info {\n background-color: #d9edf7;\n}\na.bg-info:hover {\n background-color: #afd9ee;\n}\n.bg-warning {\n background-color: #fcf8e3;\n}\na.bg-warning:hover {\n background-color: #f7ecb5;\n}\n.bg-danger {\n background-color: #f2dede;\n}\na.bg-danger:hover {\n background-color: #e4b9b9;\n}\n.page-header {\n padding-bottom: 9px;\n margin: 40px 0 20px;\n border-bottom: 1px solid #eeeeee;\n}\nul,\nol {\n margin-top: 0;\n margin-bottom: 10px;\n}\nul ul,\nol ul,\nul ol,\nol ol {\n margin-bottom: 0;\n}\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n.list-inline {\n padding-left: 0;\n list-style: none;\n margin-left: -5px;\n}\n.list-inline > li {\n display: inline-block;\n padding-left: 5px;\n padding-right: 5px;\n}\ndl {\n margin-top: 0;\n margin-bottom: 20px;\n}\ndt,\ndd {\n line-height: 1.42857143;\n}\ndt {\n font-weight: bold;\n}\ndd {\n margin-left: 0;\n}\n@media (min-width: 768px) {\n .dl-horizontal dt {\n float: left;\n width: 160px;\n clear: left;\n text-align: right;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .dl-horizontal dd {\n margin-left: 180px;\n }\n}\nabbr[title],\nabbr[data-original-title] {\n cursor: help;\n border-bottom: 1px dotted #777777;\n}\n.initialism {\n font-size: 90%;\n text-transform: uppercase;\n}\nblockquote {\n padding: 10px 20px;\n margin: 0 0 20px;\n font-size: 17.5px;\n border-left: 5px solid #eeeeee;\n}\nblockquote p:last-child,\nblockquote ul:last-child,\nblockquote ol:last-child {\n margin-bottom: 0;\n}\nblockquote footer,\nblockquote small,\nblockquote .small {\n display: block;\n font-size: 80%;\n line-height: 1.42857143;\n color: #777777;\n}\nblockquote footer:before,\nblockquote small:before,\nblockquote .small:before {\n content: '\\2014 \\00A0';\n}\n.blockquote-reverse,\nblockquote.pull-right {\n padding-right: 15px;\n padding-left: 0;\n border-right: 5px solid #eeeeee;\n border-left: 0;\n text-align: right;\n}\n.blockquote-reverse footer:before,\nblockquote.pull-right footer:before,\n.blockquote-reverse small:before,\nblockquote.pull-right small:before,\n.blockquote-reverse .small:before,\nblockquote.pull-right .small:before {\n content: '';\n}\n.blockquote-reverse footer:after,\nblockquote.pull-right footer:after,\n.blockquote-reverse small:after,\nblockquote.pull-right small:after,\n.blockquote-reverse .small:after,\nblockquote.pull-right .small:after {\n content: '\\00A0 \\2014';\n}\naddress {\n margin-bottom: 20px;\n font-style: normal;\n line-height: 1.42857143;\n}\ncode,\nkbd,\npre,\nsamp {\n font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\ncode {\n padding: 2px 4px;\n font-size: 90%;\n color: #c7254e;\n background-color: #f9f2f4;\n border-radius: 4px;\n}\nkbd {\n padding: 2px 4px;\n font-size: 90%;\n color: #ffffff;\n background-color: #333333;\n border-radius: 3px;\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\nkbd kbd {\n padding: 0;\n font-size: 100%;\n font-weight: bold;\n box-shadow: none;\n}\npre {\n display: block;\n padding: 9.5px;\n margin: 0 0 10px;\n font-size: 13px;\n line-height: 1.42857143;\n word-break: break-all;\n word-wrap: break-word;\n color: #333333;\n background-color: #f5f5f5;\n border: 1px solid #cccccc;\n border-radius: 4px;\n}\npre code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre-wrap;\n background-color: transparent;\n border-radius: 0;\n}\n.pre-scrollable {\n max-height: 340px;\n overflow-y: scroll;\n}\n.container {\n margin-right: auto;\n margin-left: auto;\n padding-left: 15px;\n padding-right: 15px;\n}\n@media (min-width: 768px) {\n .container {\n width: 750px;\n }\n}\n@media (min-width: 992px) {\n .container {\n width: 970px;\n }\n}\n@media (min-width: 1200px) {\n .container {\n width: 1170px;\n }\n}\n.container-fluid {\n margin-right: auto;\n margin-left: auto;\n padding-left: 15px;\n padding-right: 15px;\n}\n.row {\n margin-left: -15px;\n margin-right: -15px;\n}\n.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 {\n position: relative;\n min-height: 1px;\n padding-left: 15px;\n padding-right: 15px;\n}\n.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {\n float: left;\n}\n.col-xs-12 {\n width: 100%;\n}\n.col-xs-11 {\n width: 91.66666667%;\n}\n.col-xs-10 {\n width: 83.33333333%;\n}\n.col-xs-9 {\n width: 75%;\n}\n.col-xs-8 {\n width: 66.66666667%;\n}\n.col-xs-7 {\n width: 58.33333333%;\n}\n.col-xs-6 {\n width: 50%;\n}\n.col-xs-5 {\n width: 41.66666667%;\n}\n.col-xs-4 {\n width: 33.33333333%;\n}\n.col-xs-3 {\n width: 25%;\n}\n.col-xs-2 {\n width: 16.66666667%;\n}\n.col-xs-1 {\n width: 8.33333333%;\n}\n.col-xs-pull-12 {\n right: 100%;\n}\n.col-xs-pull-11 {\n right: 91.66666667%;\n}\n.col-xs-pull-10 {\n right: 83.33333333%;\n}\n.col-xs-pull-9 {\n right: 75%;\n}\n.col-xs-pull-8 {\n right: 66.66666667%;\n}\n.col-xs-pull-7 {\n right: 58.33333333%;\n}\n.col-xs-pull-6 {\n right: 50%;\n}\n.col-xs-pull-5 {\n right: 41.66666667%;\n}\n.col-xs-pull-4 {\n right: 33.33333333%;\n}\n.col-xs-pull-3 {\n right: 25%;\n}\n.col-xs-pull-2 {\n right: 16.66666667%;\n}\n.col-xs-pull-1 {\n right: 8.33333333%;\n}\n.col-xs-pull-0 {\n right: auto;\n}\n.col-xs-push-12 {\n left: 100%;\n}\n.col-xs-push-11 {\n left: 91.66666667%;\n}\n.col-xs-push-10 {\n left: 83.33333333%;\n}\n.col-xs-push-9 {\n left: 75%;\n}\n.col-xs-push-8 {\n left: 66.66666667%;\n}\n.col-xs-push-7 {\n left: 58.33333333%;\n}\n.col-xs-push-6 {\n left: 50%;\n}\n.col-xs-push-5 {\n left: 41.66666667%;\n}\n.col-xs-push-4 {\n left: 33.33333333%;\n}\n.col-xs-push-3 {\n left: 25%;\n}\n.col-xs-push-2 {\n left: 16.66666667%;\n}\n.col-xs-push-1 {\n left: 8.33333333%;\n}\n.col-xs-push-0 {\n left: auto;\n}\n.col-xs-offset-12 {\n margin-left: 100%;\n}\n.col-xs-offset-11 {\n margin-left: 91.66666667%;\n}\n.col-xs-offset-10 {\n margin-left: 83.33333333%;\n}\n.col-xs-offset-9 {\n margin-left: 75%;\n}\n.col-xs-offset-8 {\n margin-left: 66.66666667%;\n}\n.col-xs-offset-7 {\n margin-left: 58.33333333%;\n}\n.col-xs-offset-6 {\n margin-left: 50%;\n}\n.col-xs-offset-5 {\n margin-left: 41.66666667%;\n}\n.col-xs-offset-4 {\n margin-left: 33.33333333%;\n}\n.col-xs-offset-3 {\n margin-left: 25%;\n}\n.col-xs-offset-2 {\n margin-left: 16.66666667%;\n}\n.col-xs-offset-1 {\n margin-left: 8.33333333%;\n}\n.col-xs-offset-0 {\n margin-left: 0%;\n}\n@media (min-width: 768px) {\n .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 {\n float: left;\n }\n .col-sm-12 {\n width: 100%;\n }\n .col-sm-11 {\n width: 91.66666667%;\n }\n .col-sm-10 {\n width: 83.33333333%;\n }\n .col-sm-9 {\n width: 75%;\n }\n .col-sm-8 {\n width: 66.66666667%;\n }\n .col-sm-7 {\n width: 58.33333333%;\n }\n .col-sm-6 {\n width: 50%;\n }\n .col-sm-5 {\n width: 41.66666667%;\n }\n .col-sm-4 {\n width: 33.33333333%;\n }\n .col-sm-3 {\n width: 25%;\n }\n .col-sm-2 {\n width: 16.66666667%;\n }\n .col-sm-1 {\n width: 8.33333333%;\n }\n .col-sm-pull-12 {\n right: 100%;\n }\n .col-sm-pull-11 {\n right: 91.66666667%;\n }\n .col-sm-pull-10 {\n right: 83.33333333%;\n }\n .col-sm-pull-9 {\n right: 75%;\n }\n .col-sm-pull-8 {\n right: 66.66666667%;\n }\n .col-sm-pull-7 {\n right: 58.33333333%;\n }\n .col-sm-pull-6 {\n right: 50%;\n }\n .col-sm-pull-5 {\n right: 41.66666667%;\n }\n .col-sm-pull-4 {\n right: 33.33333333%;\n }\n .col-sm-pull-3 {\n right: 25%;\n }\n .col-sm-pull-2 {\n right: 16.66666667%;\n }\n .col-sm-pull-1 {\n right: 8.33333333%;\n }\n .col-sm-pull-0 {\n right: auto;\n }\n .col-sm-push-12 {\n left: 100%;\n }\n .col-sm-push-11 {\n left: 91.66666667%;\n }\n .col-sm-push-10 {\n left: 83.33333333%;\n }\n .col-sm-push-9 {\n left: 75%;\n }\n .col-sm-push-8 {\n left: 66.66666667%;\n }\n .col-sm-push-7 {\n left: 58.33333333%;\n }\n .col-sm-push-6 {\n left: 50%;\n }\n .col-sm-push-5 {\n left: 41.66666667%;\n }\n .col-sm-push-4 {\n left: 33.33333333%;\n }\n .col-sm-push-3 {\n left: 25%;\n }\n .col-sm-push-2 {\n left: 16.66666667%;\n }\n .col-sm-push-1 {\n left: 8.33333333%;\n }\n .col-sm-push-0 {\n left: auto;\n }\n .col-sm-offset-12 {\n margin-left: 100%;\n }\n .col-sm-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-sm-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-sm-offset-9 {\n margin-left: 75%;\n }\n .col-sm-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-sm-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-sm-offset-6 {\n margin-left: 50%;\n }\n .col-sm-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-sm-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-sm-offset-3 {\n margin-left: 25%;\n }\n .col-sm-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-sm-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-sm-offset-0 {\n margin-left: 0%;\n }\n}\n@media (min-width: 992px) {\n .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 {\n float: left;\n }\n .col-md-12 {\n width: 100%;\n }\n .col-md-11 {\n width: 91.66666667%;\n }\n .col-md-10 {\n width: 83.33333333%;\n }\n .col-md-9 {\n width: 75%;\n }\n .col-md-8 {\n width: 66.66666667%;\n }\n .col-md-7 {\n width: 58.33333333%;\n }\n .col-md-6 {\n width: 50%;\n }\n .col-md-5 {\n width: 41.66666667%;\n }\n .col-md-4 {\n width: 33.33333333%;\n }\n .col-md-3 {\n width: 25%;\n }\n .col-md-2 {\n width: 16.66666667%;\n }\n .col-md-1 {\n width: 8.33333333%;\n }\n .col-md-pull-12 {\n right: 100%;\n }\n .col-md-pull-11 {\n right: 91.66666667%;\n }\n .col-md-pull-10 {\n right: 83.33333333%;\n }\n .col-md-pull-9 {\n right: 75%;\n }\n .col-md-pull-8 {\n right: 66.66666667%;\n }\n .col-md-pull-7 {\n right: 58.33333333%;\n }\n .col-md-pull-6 {\n right: 50%;\n }\n .col-md-pull-5 {\n right: 41.66666667%;\n }\n .col-md-pull-4 {\n right: 33.33333333%;\n }\n .col-md-pull-3 {\n right: 25%;\n }\n .col-md-pull-2 {\n right: 16.66666667%;\n }\n .col-md-pull-1 {\n right: 8.33333333%;\n }\n .col-md-pull-0 {\n right: auto;\n }\n .col-md-push-12 {\n left: 100%;\n }\n .col-md-push-11 {\n left: 91.66666667%;\n }\n .col-md-push-10 {\n left: 83.33333333%;\n }\n .col-md-push-9 {\n left: 75%;\n }\n .col-md-push-8 {\n left: 66.66666667%;\n }\n .col-md-push-7 {\n left: 58.33333333%;\n }\n .col-md-push-6 {\n left: 50%;\n }\n .col-md-push-5 {\n left: 41.66666667%;\n }\n .col-md-push-4 {\n left: 33.33333333%;\n }\n .col-md-push-3 {\n left: 25%;\n }\n .col-md-push-2 {\n left: 16.66666667%;\n }\n .col-md-push-1 {\n left: 8.33333333%;\n }\n .col-md-push-0 {\n left: auto;\n }\n .col-md-offset-12 {\n margin-left: 100%;\n }\n .col-md-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-md-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-md-offset-9 {\n margin-left: 75%;\n }\n .col-md-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-md-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-md-offset-6 {\n margin-left: 50%;\n }\n .col-md-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-md-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-md-offset-3 {\n margin-left: 25%;\n }\n .col-md-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-md-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-md-offset-0 {\n margin-left: 0%;\n }\n}\n@media (min-width: 1200px) {\n .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 {\n float: left;\n }\n .col-lg-12 {\n width: 100%;\n }\n .col-lg-11 {\n width: 91.66666667%;\n }\n .col-lg-10 {\n width: 83.33333333%;\n }\n .col-lg-9 {\n width: 75%;\n }\n .col-lg-8 {\n width: 66.66666667%;\n }\n .col-lg-7 {\n width: 58.33333333%;\n }\n .col-lg-6 {\n width: 50%;\n }\n .col-lg-5 {\n width: 41.66666667%;\n }\n .col-lg-4 {\n width: 33.33333333%;\n }\n .col-lg-3 {\n width: 25%;\n }\n .col-lg-2 {\n width: 16.66666667%;\n }\n .col-lg-1 {\n width: 8.33333333%;\n }\n .col-lg-pull-12 {\n right: 100%;\n }\n .col-lg-pull-11 {\n right: 91.66666667%;\n }\n .col-lg-pull-10 {\n right: 83.33333333%;\n }\n .col-lg-pull-9 {\n right: 75%;\n }\n .col-lg-pull-8 {\n right: 66.66666667%;\n }\n .col-lg-pull-7 {\n right: 58.33333333%;\n }\n .col-lg-pull-6 {\n right: 50%;\n }\n .col-lg-pull-5 {\n right: 41.66666667%;\n }\n .col-lg-pull-4 {\n right: 33.33333333%;\n }\n .col-lg-pull-3 {\n right: 25%;\n }\n .col-lg-pull-2 {\n right: 16.66666667%;\n }\n .col-lg-pull-1 {\n right: 8.33333333%;\n }\n .col-lg-pull-0 {\n right: auto;\n }\n .col-lg-push-12 {\n left: 100%;\n }\n .col-lg-push-11 {\n left: 91.66666667%;\n }\n .col-lg-push-10 {\n left: 83.33333333%;\n }\n .col-lg-push-9 {\n left: 75%;\n }\n .col-lg-push-8 {\n left: 66.66666667%;\n }\n .col-lg-push-7 {\n left: 58.33333333%;\n }\n .col-lg-push-6 {\n left: 50%;\n }\n .col-lg-push-5 {\n left: 41.66666667%;\n }\n .col-lg-push-4 {\n left: 33.33333333%;\n }\n .col-lg-push-3 {\n left: 25%;\n }\n .col-lg-push-2 {\n left: 16.66666667%;\n }\n .col-lg-push-1 {\n left: 8.33333333%;\n }\n .col-lg-push-0 {\n left: auto;\n }\n .col-lg-offset-12 {\n margin-left: 100%;\n }\n .col-lg-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-lg-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-lg-offset-9 {\n margin-left: 75%;\n }\n .col-lg-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-lg-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-lg-offset-6 {\n margin-left: 50%;\n }\n .col-lg-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-lg-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-lg-offset-3 {\n margin-left: 25%;\n }\n .col-lg-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-lg-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-lg-offset-0 {\n margin-left: 0%;\n }\n}\ntable {\n background-color: transparent;\n}\ncaption {\n padding-top: 8px;\n padding-bottom: 8px;\n color: #777777;\n text-align: left;\n}\nth {\n text-align: left;\n}\n.table {\n width: 100%;\n max-width: 100%;\n margin-bottom: 20px;\n}\n.table > thead > tr > th,\n.table > tbody > tr > th,\n.table > tfoot > tr > th,\n.table > thead > tr > td,\n.table > tbody > tr > td,\n.table > tfoot > tr > td {\n padding: 8px;\n line-height: 1.42857143;\n vertical-align: top;\n border-top: 1px solid #dddddd;\n}\n.table > thead > tr > th {\n vertical-align: bottom;\n border-bottom: 2px solid #dddddd;\n}\n.table > caption + thead > tr:first-child > th,\n.table > colgroup + thead > tr:first-child > th,\n.table > thead:first-child > tr:first-child > th,\n.table > caption + thead > tr:first-child > td,\n.table > colgroup + thead > tr:first-child > td,\n.table > thead:first-child > tr:first-child > td {\n border-top: 0;\n}\n.table > tbody + tbody {\n border-top: 2px solid #dddddd;\n}\n.table .table {\n background-color: #ffffff;\n}\n.table-condensed > thead > tr > th,\n.table-condensed > tbody > tr > th,\n.table-condensed > tfoot > tr > th,\n.table-condensed > thead > tr > td,\n.table-condensed > tbody > tr > td,\n.table-condensed > tfoot > tr > td {\n padding: 5px;\n}\n.table-bordered {\n border: 1px solid #dddddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > tbody > tr > th,\n.table-bordered > tfoot > tr > th,\n.table-bordered > thead > tr > td,\n.table-bordered > tbody > tr > td,\n.table-bordered > tfoot > tr > td {\n border: 1px solid #dddddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td {\n border-bottom-width: 2px;\n}\n.table-striped > tbody > tr:nth-child(odd) {\n background-color: #f9f9f9;\n}\n.table-hover > tbody > tr:hover {\n background-color: #f5f5f5;\n}\ntable col[class*=\"col-\"] {\n position: static;\n float: none;\n display: table-column;\n}\ntable td[class*=\"col-\"],\ntable th[class*=\"col-\"] {\n position: static;\n float: none;\n display: table-cell;\n}\n.table > thead > tr > td.active,\n.table > tbody > tr > td.active,\n.table > tfoot > tr > td.active,\n.table > thead > tr > th.active,\n.table > tbody > tr > th.active,\n.table > tfoot > tr > th.active,\n.table > thead > tr.active > td,\n.table > tbody > tr.active > td,\n.table > tfoot > tr.active > td,\n.table > thead > tr.active > th,\n.table > tbody > tr.active > th,\n.table > tfoot > tr.active > th {\n background-color: #f5f5f5;\n}\n.table-hover > tbody > tr > td.active:hover,\n.table-hover > tbody > tr > th.active:hover,\n.table-hover > tbody > tr.active:hover > td,\n.table-hover > tbody > tr:hover > .active,\n.table-hover > tbody > tr.active:hover > th {\n background-color: #e8e8e8;\n}\n.table > thead > tr > td.success,\n.table > tbody > tr > td.success,\n.table > tfoot > tr > td.success,\n.table > thead > tr > th.success,\n.table > tbody > tr > th.success,\n.table > tfoot > tr > th.success,\n.table > thead > tr.success > td,\n.table > tbody > tr.success > td,\n.table > tfoot > tr.success > td,\n.table > thead > tr.success > th,\n.table > tbody > tr.success > th,\n.table > tfoot > tr.success > th {\n background-color: #dff0d8;\n}\n.table-hover > tbody > tr > td.success:hover,\n.table-hover > tbody > tr > th.success:hover,\n.table-hover > tbody > tr.success:hover > td,\n.table-hover > tbody > tr:hover > .success,\n.table-hover > tbody > tr.success:hover > th {\n background-color: #d0e9c6;\n}\n.table > thead > tr > td.info,\n.table > tbody > tr > td.info,\n.table > tfoot > tr > td.info,\n.table > thead > tr > th.info,\n.table > tbody > tr > th.info,\n.table > tfoot > tr > th.info,\n.table > thead > tr.info > td,\n.table > tbody > tr.info > td,\n.table > tfoot > tr.info > td,\n.table > thead > tr.info > th,\n.table > tbody > tr.info > th,\n.table > tfoot > tr.info > th {\n background-color: #d9edf7;\n}\n.table-hover > tbody > tr > td.info:hover,\n.table-hover > tbody > tr > th.info:hover,\n.table-hover > tbody > tr.info:hover > td,\n.table-hover > tbody > tr:hover > .info,\n.table-hover > tbody > tr.info:hover > th {\n background-color: #c4e3f3;\n}\n.table > thead > tr > td.warning,\n.table > tbody > tr > td.warning,\n.table > tfoot > tr > td.warning,\n.table > thead > tr > th.warning,\n.table > tbody > tr > th.warning,\n.table > tfoot > tr > th.warning,\n.table > thead > tr.warning > td,\n.table > tbody > tr.warning > td,\n.table > tfoot > tr.warning > td,\n.table > thead > tr.warning > th,\n.table > tbody > tr.warning > th,\n.table > tfoot > tr.warning > th {\n background-color: #fcf8e3;\n}\n.table-hover > tbody > tr > td.warning:hover,\n.table-hover > tbody > tr > th.warning:hover,\n.table-hover > tbody > tr.warning:hover > td,\n.table-hover > tbody > tr:hover > .warning,\n.table-hover > tbody > tr.warning:hover > th {\n background-color: #faf2cc;\n}\n.table > thead > tr > td.danger,\n.table > tbody > tr > td.danger,\n.table > tfoot > tr > td.danger,\n.table > thead > tr > th.danger,\n.table > tbody > tr > th.danger,\n.table > tfoot > tr > th.danger,\n.table > thead > tr.danger > td,\n.table > tbody > tr.danger > td,\n.table > tfoot > tr.danger > td,\n.table > thead > tr.danger > th,\n.table > tbody > tr.danger > th,\n.table > tfoot > tr.danger > th {\n background-color: #f2dede;\n}\n.table-hover > tbody > tr > td.danger:hover,\n.table-hover > tbody > tr > th.danger:hover,\n.table-hover > tbody > tr.danger:hover > td,\n.table-hover > tbody > tr:hover > .danger,\n.table-hover > tbody > tr.danger:hover > th {\n background-color: #ebcccc;\n}\n.table-responsive {\n overflow-x: auto;\n min-height: 0.01%;\n}\n@media screen and (max-width: 767px) {\n .table-responsive {\n width: 100%;\n margin-bottom: 15px;\n overflow-y: hidden;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n border: 1px solid #dddddd;\n }\n .table-responsive > .table {\n margin-bottom: 0;\n }\n .table-responsive > .table > thead > tr > th,\n .table-responsive > .table > tbody > tr > th,\n .table-responsive > .table > tfoot > tr > th,\n .table-responsive > .table > thead > tr > td,\n .table-responsive > .table > tbody > tr > td,\n .table-responsive > .table > tfoot > tr > td {\n white-space: nowrap;\n }\n .table-responsive > .table-bordered {\n border: 0;\n }\n .table-responsive > .table-bordered > thead > tr > th:first-child,\n .table-responsive > .table-bordered > tbody > tr > th:first-child,\n .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n .table-responsive > .table-bordered > thead > tr > td:first-child,\n .table-responsive > .table-bordered > tbody > tr > td:first-child,\n .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n border-left: 0;\n }\n .table-responsive > .table-bordered > thead > tr > th:last-child,\n .table-responsive > .table-bordered > tbody > tr > th:last-child,\n .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n .table-responsive > .table-bordered > thead > tr > td:last-child,\n .table-responsive > .table-bordered > tbody > tr > td:last-child,\n .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n border-right: 0;\n }\n .table-responsive > .table-bordered > tbody > tr:last-child > th,\n .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n .table-responsive > .table-bordered > tbody > tr:last-child > td,\n .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n border-bottom: 0;\n }\n}\nfieldset {\n padding: 0;\n margin: 0;\n border: 0;\n min-width: 0;\n}\nlegend {\n display: block;\n width: 100%;\n padding: 0;\n margin-bottom: 20px;\n font-size: 21px;\n line-height: inherit;\n color: #333333;\n border: 0;\n border-bottom: 1px solid #e5e5e5;\n}\nlabel {\n display: inline-block;\n max-width: 100%;\n margin-bottom: 5px;\n font-weight: bold;\n}\ninput[type=\"search\"] {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n margin: 4px 0 0;\n margin-top: 1px \\9;\n line-height: normal;\n}\ninput[type=\"file\"] {\n display: block;\n}\ninput[type=\"range\"] {\n display: block;\n width: 100%;\n}\nselect[multiple],\nselect[size] {\n height: auto;\n}\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n outline: thin dotted;\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\noutput {\n display: block;\n padding-top: 7px;\n font-size: 14px;\n line-height: 1.42857143;\n color: #555555;\n}\n.form-control {\n display: block;\n width: 100%;\n height: 34px;\n padding: 6px 12px;\n font-size: 14px;\n line-height: 1.42857143;\n color: #555555;\n background-color: #ffffff;\n background-image: none;\n border: 1px solid #cccccc;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n}\n.form-control:focus {\n border-color: #66afe9;\n outline: 0;\n -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);\n box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);\n}\n.form-control::-moz-placeholder {\n color: #999999;\n opacity: 1;\n}\n.form-control:-ms-input-placeholder {\n color: #999999;\n}\n.form-control::-webkit-input-placeholder {\n color: #999999;\n}\n.form-control[disabled],\n.form-control[readonly],\nfieldset[disabled] .form-control {\n cursor: not-allowed;\n background-color: #eeeeee;\n opacity: 1;\n}\ntextarea.form-control {\n height: auto;\n}\ninput[type=\"search\"] {\n -webkit-appearance: none;\n}\ninput[type=\"date\"],\ninput[type=\"time\"],\ninput[type=\"datetime-local\"],\ninput[type=\"month\"] {\n line-height: 34px;\n line-height: 1.42857143 \\0;\n}\ninput[type=\"date\"].input-sm,\ninput[type=\"time\"].input-sm,\ninput[type=\"datetime-local\"].input-sm,\ninput[type=\"month\"].input-sm {\n line-height: 30px;\n line-height: 1.5 \\0;\n}\ninput[type=\"date\"].input-lg,\ninput[type=\"time\"].input-lg,\ninput[type=\"datetime-local\"].input-lg,\ninput[type=\"month\"].input-lg {\n line-height: 46px;\n line-height: 1.33 \\0;\n}\n_:-ms-fullscreen,\n:root input[type=\"date\"],\n_:-ms-fullscreen,\n:root input[type=\"time\"],\n_:-ms-fullscreen,\n:root input[type=\"datetime-local\"],\n_:-ms-fullscreen,\n:root input[type=\"month\"] {\n line-height: 1.42857143;\n}\n_:-ms-fullscreen.input-sm,\n:root input[type=\"date\"].input-sm,\n_:-ms-fullscreen.input-sm,\n:root input[type=\"time\"].input-sm,\n_:-ms-fullscreen.input-sm,\n:root input[type=\"datetime-local\"].input-sm,\n_:-ms-fullscreen.input-sm,\n:root input[type=\"month\"].input-sm {\n line-height: 1.5;\n}\n_:-ms-fullscreen.input-lg,\n:root input[type=\"date\"].input-lg,\n_:-ms-fullscreen.input-lg,\n:root input[type=\"time\"].input-lg,\n_:-ms-fullscreen.input-lg,\n:root input[type=\"datetime-local\"].input-lg,\n_:-ms-fullscreen.input-lg,\n:root input[type=\"month\"].input-lg {\n line-height: 1.33;\n}\n.form-group {\n margin-bottom: 15px;\n}\n.radio,\n.checkbox {\n position: relative;\n display: block;\n margin-top: 10px;\n margin-bottom: 10px;\n}\n.radio label,\n.checkbox label {\n min-height: 20px;\n padding-left: 20px;\n margin-bottom: 0;\n font-weight: normal;\n cursor: pointer;\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n position: absolute;\n margin-left: -20px;\n margin-top: 4px \\9;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n margin-top: -5px;\n}\n.radio-inline,\n.checkbox-inline {\n display: inline-block;\n padding-left: 20px;\n margin-bottom: 0;\n vertical-align: middle;\n font-weight: normal;\n cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n margin-top: 0;\n margin-left: 10px;\n}\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"radio\"].disabled,\ninput[type=\"checkbox\"].disabled,\nfieldset[disabled] input[type=\"radio\"],\nfieldset[disabled] input[type=\"checkbox\"] {\n cursor: not-allowed;\n}\n.radio-inline.disabled,\n.checkbox-inline.disabled,\nfieldset[disabled] .radio-inline,\nfieldset[disabled] .checkbox-inline {\n cursor: not-allowed;\n}\n.radio.disabled label,\n.checkbox.disabled label,\nfieldset[disabled] .radio label,\nfieldset[disabled] .checkbox label {\n cursor: not-allowed;\n}\n.form-control-static {\n padding-top: 7px;\n padding-bottom: 7px;\n margin-bottom: 0;\n}\n.form-control-static.input-lg,\n.form-control-static.input-sm {\n padding-left: 0;\n padding-right: 0;\n}\n.input-sm,\n.form-group-sm .form-control {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\nselect.input-sm,\nselect.form-group-sm .form-control {\n height: 30px;\n line-height: 30px;\n}\ntextarea.input-sm,\ntextarea.form-group-sm .form-control,\nselect[multiple].input-sm,\nselect[multiple].form-group-sm .form-control {\n height: auto;\n}\n.input-lg,\n.form-group-lg .form-control {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.33;\n border-radius: 6px;\n}\nselect.input-lg,\nselect.form-group-lg .form-control {\n height: 46px;\n line-height: 46px;\n}\ntextarea.input-lg,\ntextarea.form-group-lg .form-control,\nselect[multiple].input-lg,\nselect[multiple].form-group-lg .form-control {\n height: auto;\n}\n.has-feedback {\n position: relative;\n}\n.has-feedback .form-control {\n padding-right: 42.5px;\n}\n.form-control-feedback {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2;\n display: block;\n width: 34px;\n height: 34px;\n line-height: 34px;\n text-align: center;\n pointer-events: none;\n}\n.input-lg + .form-control-feedback {\n width: 46px;\n height: 46px;\n line-height: 46px;\n}\n.input-sm + .form-control-feedback {\n width: 30px;\n height: 30px;\n line-height: 30px;\n}\n.has-success .help-block,\n.has-success .control-label,\n.has-success .radio,\n.has-success .checkbox,\n.has-success .radio-inline,\n.has-success .checkbox-inline,\n.has-success.radio label,\n.has-success.checkbox label,\n.has-success.radio-inline label,\n.has-success.checkbox-inline label {\n color: #3c763d;\n}\n.has-success .form-control {\n border-color: #3c763d;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-success .form-control:focus {\n border-color: #2b542c;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;\n}\n.has-success .input-group-addon {\n color: #3c763d;\n border-color: #3c763d;\n background-color: #dff0d8;\n}\n.has-success .form-control-feedback {\n color: #3c763d;\n}\n.has-warning .help-block,\n.has-warning .control-label,\n.has-warning .radio,\n.has-warning .checkbox,\n.has-warning .radio-inline,\n.has-warning .checkbox-inline,\n.has-warning.radio label,\n.has-warning.checkbox label,\n.has-warning.radio-inline label,\n.has-warning.checkbox-inline label {\n color: #8a6d3b;\n}\n.has-warning .form-control {\n border-color: #8a6d3b;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-warning .form-control:focus {\n border-color: #66512c;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;\n}\n.has-warning .input-group-addon {\n color: #8a6d3b;\n border-color: #8a6d3b;\n background-color: #fcf8e3;\n}\n.has-warning .form-control-feedback {\n color: #8a6d3b;\n}\n.has-error .help-block,\n.has-error .control-label,\n.has-error .radio,\n.has-error .checkbox,\n.has-error .radio-inline,\n.has-error .checkbox-inline,\n.has-error.radio label,\n.has-error.checkbox label,\n.has-error.radio-inline label,\n.has-error.checkbox-inline label {\n color: #a94442;\n}\n.has-error .form-control {\n border-color: #a94442;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-error .form-control:focus {\n border-color: #843534;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;\n}\n.has-error .input-group-addon {\n color: #a94442;\n border-color: #a94442;\n background-color: #f2dede;\n}\n.has-error .form-control-feedback {\n color: #a94442;\n}\n.has-feedback label ~ .form-control-feedback {\n top: 25px;\n}\n.has-feedback label.sr-only ~ .form-control-feedback {\n top: 0;\n}\n.help-block {\n display: block;\n margin-top: 5px;\n margin-bottom: 10px;\n color: #737373;\n}\n@media (min-width: 768px) {\n .form-inline .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .form-inline .form-control-static {\n display: inline-block;\n }\n .form-inline .input-group {\n display: inline-table;\n vertical-align: middle;\n }\n .form-inline .input-group .input-group-addon,\n .form-inline .input-group .input-group-btn,\n .form-inline .input-group .form-control {\n width: auto;\n }\n .form-inline .input-group > .form-control {\n width: 100%;\n }\n .form-inline .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .radio,\n .form-inline .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .radio label,\n .form-inline .checkbox label {\n padding-left: 0;\n }\n .form-inline .radio input[type=\"radio\"],\n .form-inline .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n .form-inline .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n margin-top: 0;\n margin-bottom: 0;\n padding-top: 7px;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n min-height: 27px;\n}\n.form-horizontal .form-group {\n margin-left: -15px;\n margin-right: -15px;\n}\n@media (min-width: 768px) {\n .form-horizontal .control-label {\n text-align: right;\n margin-bottom: 0;\n padding-top: 7px;\n }\n}\n.form-horizontal .has-feedback .form-control-feedback {\n right: 15px;\n}\n@media (min-width: 768px) {\n .form-horizontal .form-group-lg .control-label {\n padding-top: 14.3px;\n }\n}\n@media (min-width: 768px) {\n .form-horizontal .form-group-sm .control-label {\n padding-top: 6px;\n }\n}\n.btn {\n display: inline-block;\n margin-bottom: 0;\n font-weight: normal;\n text-align: center;\n vertical-align: middle;\n touch-action: manipulation;\n cursor: pointer;\n background-image: none;\n border: 1px solid transparent;\n white-space: nowrap;\n padding: 6px 12px;\n font-size: 14px;\n line-height: 1.42857143;\n border-radius: 4px;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n.btn:focus,\n.btn:active:focus,\n.btn.active:focus,\n.btn.focus,\n.btn:active.focus,\n.btn.active.focus {\n outline: thin dotted;\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n.btn:hover,\n.btn:focus,\n.btn.focus {\n color: #333333;\n text-decoration: none;\n}\n.btn:active,\n.btn.active {\n outline: 0;\n background-image: none;\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn.disabled,\n.btn[disabled],\nfieldset[disabled] .btn {\n cursor: not-allowed;\n pointer-events: none;\n opacity: 0.65;\n filter: alpha(opacity=65);\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn-default {\n color: #333333;\n background-color: #ffffff;\n border-color: #cccccc;\n}\n.btn-default:hover,\n.btn-default:focus,\n.btn-default.focus,\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n color: #333333;\n background-color: #e6e6e6;\n border-color: #adadad;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n background-image: none;\n}\n.btn-default.disabled,\n.btn-default[disabled],\nfieldset[disabled] .btn-default,\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus,\n.btn-default.disabled:active,\n.btn-default[disabled]:active,\nfieldset[disabled] .btn-default:active,\n.btn-default.disabled.active,\n.btn-default[disabled].active,\nfieldset[disabled] .btn-default.active {\n background-color: #ffffff;\n border-color: #cccccc;\n}\n.btn-default .badge {\n color: #ffffff;\n background-color: #333333;\n}\n.btn-primary {\n color: #ffffff;\n background-color: #428bca;\n border-color: #357ebd;\n}\n.btn-primary:hover,\n.btn-primary:focus,\n.btn-primary.focus,\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n color: #ffffff;\n background-color: #3071a9;\n border-color: #285e8e;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n background-image: none;\n}\n.btn-primary.disabled,\n.btn-primary[disabled],\nfieldset[disabled] .btn-primary,\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus,\n.btn-primary.disabled:active,\n.btn-primary[disabled]:active,\nfieldset[disabled] .btn-primary:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled].active,\nfieldset[disabled] .btn-primary.active {\n background-color: #428bca;\n border-color: #357ebd;\n}\n.btn-primary .badge {\n color: #428bca;\n background-color: #ffffff;\n}\n.btn-success {\n color: #ffffff;\n background-color: #5cb85c;\n border-color: #4cae4c;\n}\n.btn-success:hover,\n.btn-success:focus,\n.btn-success.focus,\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n color: #ffffff;\n background-color: #449d44;\n border-color: #398439;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n background-image: none;\n}\n.btn-success.disabled,\n.btn-success[disabled],\nfieldset[disabled] .btn-success,\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus,\n.btn-success.disabled:active,\n.btn-success[disabled]:active,\nfieldset[disabled] .btn-success:active,\n.btn-success.disabled.active,\n.btn-success[disabled].active,\nfieldset[disabled] .btn-success.active {\n background-color: #5cb85c;\n border-color: #4cae4c;\n}\n.btn-success .badge {\n color: #5cb85c;\n background-color: #ffffff;\n}\n.btn-info {\n color: #ffffff;\n background-color: #5bc0de;\n border-color: #46b8da;\n}\n.btn-info:hover,\n.btn-info:focus,\n.btn-info.focus,\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n color: #ffffff;\n background-color: #31b0d5;\n border-color: #269abc;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n background-image: none;\n}\n.btn-info.disabled,\n.btn-info[disabled],\nfieldset[disabled] .btn-info,\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus,\n.btn-info.disabled:active,\n.btn-info[disabled]:active,\nfieldset[disabled] .btn-info:active,\n.btn-info.disabled.active,\n.btn-info[disabled].active,\nfieldset[disabled] .btn-info.active {\n background-color: #5bc0de;\n border-color: #46b8da;\n}\n.btn-info .badge {\n color: #5bc0de;\n background-color: #ffffff;\n}\n.btn-warning {\n color: #ffffff;\n background-color: #f0ad4e;\n border-color: #eea236;\n}\n.btn-warning:hover,\n.btn-warning:focus,\n.btn-warning.focus,\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n color: #ffffff;\n background-color: #ec971f;\n border-color: #d58512;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n background-image: none;\n}\n.btn-warning.disabled,\n.btn-warning[disabled],\nfieldset[disabled] .btn-warning,\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus,\n.btn-warning.disabled:active,\n.btn-warning[disabled]:active,\nfieldset[disabled] .btn-warning:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled].active,\nfieldset[disabled] .btn-warning.active {\n background-color: #f0ad4e;\n border-color: #eea236;\n}\n.btn-warning .badge {\n color: #f0ad4e;\n background-color: #ffffff;\n}\n.btn-danger {\n color: #ffffff;\n background-color: #d9534f;\n border-color: #d43f3a;\n}\n.btn-danger:hover,\n.btn-danger:focus,\n.btn-danger.focus,\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n color: #ffffff;\n background-color: #c9302c;\n border-color: #ac2925;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n background-image: none;\n}\n.btn-danger.disabled,\n.btn-danger[disabled],\nfieldset[disabled] .btn-danger,\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus,\n.btn-danger.disabled:active,\n.btn-danger[disabled]:active,\nfieldset[disabled] .btn-danger:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled].active,\nfieldset[disabled] .btn-danger.active {\n background-color: #d9534f;\n border-color: #d43f3a;\n}\n.btn-danger .badge {\n color: #d9534f;\n background-color: #ffffff;\n}\n.btn-link {\n color: #428bca;\n font-weight: normal;\n border-radius: 0;\n}\n.btn-link,\n.btn-link:active,\n.btn-link.active,\n.btn-link[disabled],\nfieldset[disabled] .btn-link {\n background-color: transparent;\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn-link,\n.btn-link:hover,\n.btn-link:focus,\n.btn-link:active {\n border-color: transparent;\n}\n.btn-link:hover,\n.btn-link:focus {\n color: #2a6496;\n text-decoration: underline;\n background-color: transparent;\n}\n.btn-link[disabled]:hover,\nfieldset[disabled] .btn-link:hover,\n.btn-link[disabled]:focus,\nfieldset[disabled] .btn-link:focus {\n color: #777777;\n text-decoration: none;\n}\n.btn-lg,\n.btn-group-lg > .btn {\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.33;\n border-radius: 6px;\n}\n.btn-sm,\n.btn-group-sm > .btn {\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.btn-xs,\n.btn-group-xs > .btn {\n padding: 1px 5px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.btn-block {\n display: block;\n width: 100%;\n}\n.btn-block + .btn-block {\n margin-top: 5px;\n}\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n width: 100%;\n}\n.fade {\n opacity: 0;\n -webkit-transition: opacity 0.15s linear;\n -o-transition: opacity 0.15s linear;\n transition: opacity 0.15s linear;\n}\n.fade.in {\n opacity: 1;\n}\n.collapse {\n display: none;\n visibility: hidden;\n}\n.collapse.in {\n display: block;\n visibility: visible;\n}\ntr.collapse.in {\n display: table-row;\n}\ntbody.collapse.in {\n display: table-row-group;\n}\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n -webkit-transition-property: height, visibility;\n transition-property: height, visibility;\n -webkit-transition-duration: 0.35s;\n transition-duration: 0.35s;\n -webkit-transition-timing-function: ease;\n transition-timing-function: ease;\n}\n.caret {\n display: inline-block;\n width: 0;\n height: 0;\n margin-left: 2px;\n vertical-align: middle;\n border-top: 4px solid;\n border-right: 4px solid transparent;\n border-left: 4px solid transparent;\n}\n.dropdown {\n position: relative;\n}\n.dropdown-toggle:focus {\n outline: 0;\n}\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: 1000;\n display: none;\n float: left;\n min-width: 160px;\n padding: 5px 0;\n margin: 2px 0 0;\n list-style: none;\n font-size: 14px;\n text-align: left;\n background-color: #ffffff;\n border: 1px solid #cccccc;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 4px;\n -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n background-clip: padding-box;\n}\n.dropdown-menu.pull-right {\n right: 0;\n left: auto;\n}\n.dropdown-menu .divider {\n height: 1px;\n margin: 9px 0;\n overflow: hidden;\n background-color: #e5e5e5;\n}\n.dropdown-menu > li > a {\n display: block;\n padding: 3px 20px;\n clear: both;\n font-weight: normal;\n line-height: 1.42857143;\n color: #333333;\n white-space: nowrap;\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n text-decoration: none;\n color: #262626;\n background-color: #f5f5f5;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n color: #ffffff;\n text-decoration: none;\n outline: 0;\n background-color: #428bca;\n}\n.dropdown-menu > .disabled > a,\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n color: #777777;\n}\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n text-decoration: none;\n background-color: transparent;\n background-image: none;\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n cursor: not-allowed;\n}\n.open > .dropdown-menu {\n display: block;\n}\n.open > a {\n outline: 0;\n}\n.dropdown-menu-right {\n left: auto;\n right: 0;\n}\n.dropdown-menu-left {\n left: 0;\n right: auto;\n}\n.dropdown-header {\n display: block;\n padding: 3px 20px;\n font-size: 12px;\n line-height: 1.42857143;\n color: #777777;\n white-space: nowrap;\n}\n.dropdown-backdrop {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n top: 0;\n z-index: 990;\n}\n.pull-right > .dropdown-menu {\n right: 0;\n left: auto;\n}\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n border-top: 0;\n border-bottom: 4px solid;\n content: \"\";\n}\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n top: auto;\n bottom: 100%;\n margin-bottom: 1px;\n}\n@media (min-width: 768px) {\n .navbar-right .dropdown-menu {\n left: auto;\n right: 0;\n }\n .navbar-right .dropdown-menu-left {\n left: 0;\n right: auto;\n }\n}\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-block;\n vertical-align: middle;\n}\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n position: relative;\n float: left;\n}\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group-vertical > .btn:focus,\n.btn-group > .btn:active,\n.btn-group-vertical > .btn:active,\n.btn-group > .btn.active,\n.btn-group-vertical > .btn.active {\n z-index: 2;\n}\n.btn-group > .btn:focus,\n.btn-group-vertical > .btn:focus {\n outline: 0;\n}\n.btn-group .btn + .btn,\n.btn-group .btn + .btn-group,\n.btn-group .btn-group + .btn,\n.btn-group .btn-group + .btn-group {\n margin-left: -1px;\n}\n.btn-toolbar {\n margin-left: -5px;\n}\n.btn-toolbar .btn-group,\n.btn-toolbar .input-group {\n float: left;\n}\n.btn-toolbar > .btn,\n.btn-toolbar > .btn-group,\n.btn-toolbar > .input-group {\n margin-left: 5px;\n}\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n border-radius: 0;\n}\n.btn-group > .btn:first-child {\n margin-left: 0;\n}\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n border-bottom-right-radius: 0;\n border-top-right-radius: 0;\n}\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n border-bottom-left-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group > .btn-group {\n float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group > .btn-group:first-child > .btn:last-child,\n.btn-group > .btn-group:first-child > .dropdown-toggle {\n border-bottom-right-radius: 0;\n border-top-right-radius: 0;\n}\n.btn-group > .btn-group:last-child > .btn:first-child {\n border-bottom-left-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n outline: 0;\n}\n.btn-group > .btn + .dropdown-toggle {\n padding-left: 8px;\n padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n padding-left: 12px;\n padding-right: 12px;\n}\n.btn-group.open .dropdown-toggle {\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-group.open .dropdown-toggle.btn-link {\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn .caret {\n margin-left: 0;\n}\n.btn-lg .caret {\n border-width: 5px 5px 0;\n border-bottom-width: 0;\n}\n.dropup .btn-lg .caret {\n border-width: 0 5px 5px;\n}\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group,\n.btn-group-vertical > .btn-group > .btn {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n}\n.btn-group-vertical > .btn-group > .btn {\n float: none;\n}\n.btn-group-vertical > .btn + .btn,\n.btn-group-vertical > .btn + .btn-group,\n.btn-group-vertical > .btn-group + .btn,\n.btn-group-vertical > .btn-group + .btn-group {\n margin-top: -1px;\n margin-left: 0;\n}\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n.btn-group-vertical > .btn:first-child:not(:last-child) {\n border-top-right-radius: 4px;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn:last-child:not(:first-child) {\n border-bottom-left-radius: 4px;\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group-justified {\n display: table;\n width: 100%;\n table-layout: fixed;\n border-collapse: separate;\n}\n.btn-group-justified > .btn,\n.btn-group-justified > .btn-group {\n float: none;\n display: table-cell;\n width: 1%;\n}\n.btn-group-justified > .btn-group .btn {\n width: 100%;\n}\n.btn-group-justified > .btn-group .dropdown-menu {\n left: auto;\n}\n[data-toggle=\"buttons\"] > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn input[type=\"checkbox\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"checkbox\"] {\n position: absolute;\n clip: rect(0, 0, 0, 0);\n pointer-events: none;\n}\n.input-group {\n position: relative;\n display: table;\n border-collapse: separate;\n}\n.input-group[class*=\"col-\"] {\n float: none;\n padding-left: 0;\n padding-right: 0;\n}\n.input-group .form-control {\n position: relative;\n z-index: 2;\n float: left;\n width: 100%;\n margin-bottom: 0;\n}\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.33;\n border-radius: 6px;\n}\nselect.input-group-lg > .form-control,\nselect.input-group-lg > .input-group-addon,\nselect.input-group-lg > .input-group-btn > .btn {\n height: 46px;\n line-height: 46px;\n}\ntextarea.input-group-lg > .form-control,\ntextarea.input-group-lg > .input-group-addon,\ntextarea.input-group-lg > .input-group-btn > .btn,\nselect[multiple].input-group-lg > .form-control,\nselect[multiple].input-group-lg > .input-group-addon,\nselect[multiple].input-group-lg > .input-group-btn > .btn {\n height: auto;\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\nselect.input-group-sm > .form-control,\nselect.input-group-sm > .input-group-addon,\nselect.input-group-sm > .input-group-btn > .btn {\n height: 30px;\n line-height: 30px;\n}\ntextarea.input-group-sm > .form-control,\ntextarea.input-group-sm > .input-group-addon,\ntextarea.input-group-sm > .input-group-btn > .btn,\nselect[multiple].input-group-sm > .form-control,\nselect[multiple].input-group-sm > .input-group-addon,\nselect[multiple].input-group-sm > .input-group-btn > .btn {\n height: auto;\n}\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n display: table-cell;\n}\n.input-group-addon:not(:first-child):not(:last-child),\n.input-group-btn:not(:first-child):not(:last-child),\n.input-group .form-control:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n.input-group-addon,\n.input-group-btn {\n width: 1%;\n white-space: nowrap;\n vertical-align: middle;\n}\n.input-group-addon {\n padding: 6px 12px;\n font-size: 14px;\n font-weight: normal;\n line-height: 1;\n color: #555555;\n text-align: center;\n background-color: #eeeeee;\n border: 1px solid #cccccc;\n border-radius: 4px;\n}\n.input-group-addon.input-sm {\n padding: 5px 10px;\n font-size: 12px;\n border-radius: 3px;\n}\n.input-group-addon.input-lg {\n padding: 10px 16px;\n font-size: 18px;\n border-radius: 6px;\n}\n.input-group-addon input[type=\"radio\"],\n.input-group-addon input[type=\"checkbox\"] {\n margin-top: 0;\n}\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n border-bottom-right-radius: 0;\n border-top-right-radius: 0;\n}\n.input-group-addon:first-child {\n border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n border-bottom-left-radius: 0;\n border-top-left-radius: 0;\n}\n.input-group-addon:last-child {\n border-left: 0;\n}\n.input-group-btn {\n position: relative;\n font-size: 0;\n white-space: nowrap;\n}\n.input-group-btn > .btn {\n position: relative;\n}\n.input-group-btn > .btn + .btn {\n margin-left: -1px;\n}\n.input-group-btn > .btn:hover,\n.input-group-btn > .btn:focus,\n.input-group-btn > .btn:active {\n z-index: 2;\n}\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group {\n margin-right: -1px;\n}\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group {\n margin-left: -1px;\n}\n.nav {\n margin-bottom: 0;\n padding-left: 0;\n list-style: none;\n}\n.nav > li {\n position: relative;\n display: block;\n}\n.nav > li > a {\n position: relative;\n display: block;\n padding: 10px 15px;\n}\n.nav > li > a:hover,\n.nav > li > a:focus {\n text-decoration: none;\n background-color: #eeeeee;\n}\n.nav > li.disabled > a {\n color: #777777;\n}\n.nav > li.disabled > a:hover,\n.nav > li.disabled > a:focus {\n color: #777777;\n text-decoration: none;\n background-color: transparent;\n cursor: not-allowed;\n}\n.nav .open > a,\n.nav .open > a:hover,\n.nav .open > a:focus {\n background-color: #eeeeee;\n border-color: #428bca;\n}\n.nav .nav-divider {\n height: 1px;\n margin: 9px 0;\n overflow: hidden;\n background-color: #e5e5e5;\n}\n.nav > li > a > img {\n max-width: none;\n}\n.nav-tabs {\n border-bottom: 1px solid #dddddd;\n}\n.nav-tabs > li {\n float: left;\n margin-bottom: -1px;\n}\n.nav-tabs > li > a {\n margin-right: 2px;\n line-height: 1.42857143;\n border: 1px solid transparent;\n border-radius: 4px 4px 0 0;\n}\n.nav-tabs > li > a:hover {\n border-color: #eeeeee #eeeeee #dddddd;\n}\n.nav-tabs > li.active > a,\n.nav-tabs > li.active > a:hover,\n.nav-tabs > li.active > a:focus {\n color: #555555;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n border-bottom-color: transparent;\n cursor: default;\n}\n.nav-tabs.nav-justified {\n width: 100%;\n border-bottom: 0;\n}\n.nav-tabs.nav-justified > li {\n float: none;\n}\n.nav-tabs.nav-justified > li > a {\n text-align: center;\n margin-bottom: 5px;\n}\n.nav-tabs.nav-justified > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n}\n@media (min-width: 768px) {\n .nav-tabs.nav-justified > li {\n display: table-cell;\n width: 1%;\n }\n .nav-tabs.nav-justified > li > a {\n margin-bottom: 0;\n }\n}\n.nav-tabs.nav-justified > li > a {\n margin-right: 0;\n border-radius: 4px;\n}\n.nav-tabs.nav-justified > .active > a,\n.nav-tabs.nav-justified > .active > a:hover,\n.nav-tabs.nav-justified > .active > a:focus {\n border: 1px solid #dddddd;\n}\n@media (min-width: 768px) {\n .nav-tabs.nav-justified > li > a {\n border-bottom: 1px solid #dddddd;\n border-radius: 4px 4px 0 0;\n }\n .nav-tabs.nav-justified > .active > a,\n .nav-tabs.nav-justified > .active > a:hover,\n .nav-tabs.nav-justified > .active > a:focus {\n border-bottom-color: #ffffff;\n }\n}\n.nav-pills > li {\n float: left;\n}\n.nav-pills > li > a {\n border-radius: 4px;\n}\n.nav-pills > li + li {\n margin-left: 2px;\n}\n.nav-pills > li.active > a,\n.nav-pills > li.active > a:hover,\n.nav-pills > li.active > a:focus {\n color: #ffffff;\n background-color: #428bca;\n}\n.nav-stacked > li {\n float: none;\n}\n.nav-stacked > li + li {\n margin-top: 2px;\n margin-left: 0;\n}\n.nav-justified {\n width: 100%;\n}\n.nav-justified > li {\n float: none;\n}\n.nav-justified > li > a {\n text-align: center;\n margin-bottom: 5px;\n}\n.nav-justified > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n}\n@media (min-width: 768px) {\n .nav-justified > li {\n display: table-cell;\n width: 1%;\n }\n .nav-justified > li > a {\n margin-bottom: 0;\n }\n}\n.nav-tabs-justified {\n border-bottom: 0;\n}\n.nav-tabs-justified > li > a {\n margin-right: 0;\n border-radius: 4px;\n}\n.nav-tabs-justified > .active > a,\n.nav-tabs-justified > .active > a:hover,\n.nav-tabs-justified > .active > a:focus {\n border: 1px solid #dddddd;\n}\n@media (min-width: 768px) {\n .nav-tabs-justified > li > a {\n border-bottom: 1px solid #dddddd;\n border-radius: 4px 4px 0 0;\n }\n .nav-tabs-justified > .active > a,\n .nav-tabs-justified > .active > a:hover,\n .nav-tabs-justified > .active > a:focus {\n border-bottom-color: #ffffff;\n }\n}\n.tab-content > .tab-pane {\n display: none;\n visibility: hidden;\n}\n.tab-content > .active {\n display: block;\n visibility: visible;\n}\n.nav-tabs .dropdown-menu {\n margin-top: -1px;\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.navbar {\n position: relative;\n min-height: 50px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n}\n@media (min-width: 768px) {\n .navbar {\n border-radius: 4px;\n }\n}\n@media (min-width: 768px) {\n .navbar-header {\n float: left;\n }\n}\n.navbar-collapse {\n overflow-x: visible;\n padding-right: 15px;\n padding-left: 15px;\n border-top: 1px solid transparent;\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);\n -webkit-overflow-scrolling: touch;\n}\n.navbar-collapse.in {\n overflow-y: auto;\n}\n@media (min-width: 768px) {\n .navbar-collapse {\n width: auto;\n border-top: 0;\n box-shadow: none;\n }\n .navbar-collapse.collapse {\n display: block !important;\n visibility: visible !important;\n height: auto !important;\n padding-bottom: 0;\n overflow: visible !important;\n }\n .navbar-collapse.in {\n overflow-y: visible;\n }\n .navbar-fixed-top .navbar-collapse,\n .navbar-static-top .navbar-collapse,\n .navbar-fixed-bottom .navbar-collapse {\n padding-left: 0;\n padding-right: 0;\n }\n}\n.navbar-fixed-top .navbar-collapse,\n.navbar-fixed-bottom .navbar-collapse {\n max-height: 340px;\n}\n@media (max-device-width: 480px) and (orientation: landscape) {\n .navbar-fixed-top .navbar-collapse,\n .navbar-fixed-bottom .navbar-collapse {\n max-height: 200px;\n }\n}\n.container > .navbar-header,\n.container-fluid > .navbar-header,\n.container > .navbar-collapse,\n.container-fluid > .navbar-collapse {\n margin-right: -15px;\n margin-left: -15px;\n}\n@media (min-width: 768px) {\n .container > .navbar-header,\n .container-fluid > .navbar-header,\n .container > .navbar-collapse,\n .container-fluid > .navbar-collapse {\n margin-right: 0;\n margin-left: 0;\n }\n}\n.navbar-static-top {\n z-index: 1000;\n border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n .navbar-static-top {\n border-radius: 0;\n }\n}\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n position: fixed;\n right: 0;\n left: 0;\n z-index: 1030;\n}\n@media (min-width: 768px) {\n .navbar-fixed-top,\n .navbar-fixed-bottom {\n border-radius: 0;\n }\n}\n.navbar-fixed-top {\n top: 0;\n border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n bottom: 0;\n margin-bottom: 0;\n border-width: 1px 0 0;\n}\n.navbar-brand {\n float: left;\n padding: 15px 15px;\n font-size: 18px;\n line-height: 20px;\n height: 50px;\n}\n.navbar-brand:hover,\n.navbar-brand:focus {\n text-decoration: none;\n}\n.navbar-brand > img {\n display: block;\n}\n@media (min-width: 768px) {\n .navbar > .container .navbar-brand,\n .navbar > .container-fluid .navbar-brand {\n margin-left: -15px;\n }\n}\n.navbar-toggle {\n position: relative;\n float: right;\n margin-right: 15px;\n padding: 9px 10px;\n margin-top: 8px;\n margin-bottom: 8px;\n background-color: transparent;\n background-image: none;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.navbar-toggle:focus {\n outline: 0;\n}\n.navbar-toggle .icon-bar {\n display: block;\n width: 22px;\n height: 2px;\n border-radius: 1px;\n}\n.navbar-toggle .icon-bar + .icon-bar {\n margin-top: 4px;\n}\n@media (min-width: 768px) {\n .navbar-toggle {\n display: none;\n }\n}\n.navbar-nav {\n margin: 7.5px -15px;\n}\n.navbar-nav > li > a {\n padding-top: 10px;\n padding-bottom: 10px;\n line-height: 20px;\n}\n@media (max-width: 767px) {\n .navbar-nav .open .dropdown-menu {\n position: static;\n float: none;\n width: auto;\n margin-top: 0;\n background-color: transparent;\n border: 0;\n box-shadow: none;\n }\n .navbar-nav .open .dropdown-menu > li > a,\n .navbar-nav .open .dropdown-menu .dropdown-header {\n padding: 5px 15px 5px 25px;\n }\n .navbar-nav .open .dropdown-menu > li > a {\n line-height: 20px;\n }\n .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-nav .open .dropdown-menu > li > a:focus {\n background-image: none;\n }\n}\n@media (min-width: 768px) {\n .navbar-nav {\n float: left;\n margin: 0;\n }\n .navbar-nav > li {\n float: left;\n }\n .navbar-nav > li > a {\n padding-top: 15px;\n padding-bottom: 15px;\n }\n}\n.navbar-form {\n margin-left: -15px;\n margin-right: -15px;\n padding: 10px 15px;\n border-top: 1px solid transparent;\n border-bottom: 1px solid transparent;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n margin-top: 8px;\n margin-bottom: 8px;\n}\n@media (min-width: 768px) {\n .navbar-form .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .navbar-form .form-control-static {\n display: inline-block;\n }\n .navbar-form .input-group {\n display: inline-table;\n vertical-align: middle;\n }\n .navbar-form .input-group .input-group-addon,\n .navbar-form .input-group .input-group-btn,\n .navbar-form .input-group .form-control {\n width: auto;\n }\n .navbar-form .input-group > .form-control {\n width: 100%;\n }\n .navbar-form .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .radio,\n .navbar-form .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .radio label,\n .navbar-form .checkbox label {\n padding-left: 0;\n }\n .navbar-form .radio input[type=\"radio\"],\n .navbar-form .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n .navbar-form .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n@media (max-width: 767px) {\n .navbar-form .form-group {\n margin-bottom: 5px;\n }\n .navbar-form .form-group:last-child {\n margin-bottom: 0;\n }\n}\n@media (min-width: 768px) {\n .navbar-form {\n width: auto;\n border: 0;\n margin-left: 0;\n margin-right: 0;\n padding-top: 0;\n padding-bottom: 0;\n -webkit-box-shadow: none;\n box-shadow: none;\n }\n}\n.navbar-nav > li > .dropdown-menu {\n margin-top: 0;\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.navbar-btn {\n margin-top: 8px;\n margin-bottom: 8px;\n}\n.navbar-btn.btn-sm {\n margin-top: 10px;\n margin-bottom: 10px;\n}\n.navbar-btn.btn-xs {\n margin-top: 14px;\n margin-bottom: 14px;\n}\n.navbar-text {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n@media (min-width: 768px) {\n .navbar-text {\n float: left;\n margin-left: 15px;\n margin-right: 15px;\n }\n}\n@media (min-width: 768px) {\n .navbar-left {\n float: left !important;\n }\n .navbar-right {\n float: right !important;\n margin-right: -15px;\n }\n .navbar-right ~ .navbar-right {\n margin-right: 0;\n }\n}\n.navbar-default {\n background-color: #f8f8f8;\n border-color: #e7e7e7;\n}\n.navbar-default .navbar-brand {\n color: #777777;\n}\n.navbar-default .navbar-brand:hover,\n.navbar-default .navbar-brand:focus {\n color: #5e5e5e;\n background-color: transparent;\n}\n.navbar-default .navbar-text {\n color: #777777;\n}\n.navbar-default .navbar-nav > li > a {\n color: #777777;\n}\n.navbar-default .navbar-nav > li > a:hover,\n.navbar-default .navbar-nav > li > a:focus {\n color: #333333;\n background-color: transparent;\n}\n.navbar-default .navbar-nav > .active > a,\n.navbar-default .navbar-nav > .active > a:hover,\n.navbar-default .navbar-nav > .active > a:focus {\n color: #555555;\n background-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .disabled > a,\n.navbar-default .navbar-nav > .disabled > a:hover,\n.navbar-default .navbar-nav > .disabled > a:focus {\n color: #cccccc;\n background-color: transparent;\n}\n.navbar-default .navbar-toggle {\n border-color: #dddddd;\n}\n.navbar-default .navbar-toggle:hover,\n.navbar-default .navbar-toggle:focus {\n background-color: #dddddd;\n}\n.navbar-default .navbar-toggle .icon-bar {\n background-color: #888888;\n}\n.navbar-default .navbar-collapse,\n.navbar-default .navbar-form {\n border-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .open > a:hover,\n.navbar-default .navbar-nav > .open > a:focus {\n background-color: #e7e7e7;\n color: #555555;\n}\n@media (max-width: 767px) {\n .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n color: #777777;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\n color: #333333;\n background-color: transparent;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a,\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #555555;\n background-color: #e7e7e7;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n color: #cccccc;\n background-color: transparent;\n }\n}\n.navbar-default .navbar-link {\n color: #777777;\n}\n.navbar-default .navbar-link:hover {\n color: #333333;\n}\n.navbar-default .btn-link {\n color: #777777;\n}\n.navbar-default .btn-link:hover,\n.navbar-default .btn-link:focus {\n color: #333333;\n}\n.navbar-default .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-default .btn-link:hover,\n.navbar-default .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-default .btn-link:focus {\n color: #cccccc;\n}\n.navbar-inverse {\n background-color: #222222;\n border-color: #080808;\n}\n.navbar-inverse .navbar-brand {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-brand:hover,\n.navbar-inverse .navbar-brand:focus {\n color: #ffffff;\n background-color: transparent;\n}\n.navbar-inverse .navbar-text {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a:hover,\n.navbar-inverse .navbar-nav > li > a:focus {\n color: #ffffff;\n background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .active > a,\n.navbar-inverse .navbar-nav > .active > a:hover,\n.navbar-inverse .navbar-nav > .active > a:focus {\n color: #ffffff;\n background-color: #080808;\n}\n.navbar-inverse .navbar-nav > .disabled > a,\n.navbar-inverse .navbar-nav > .disabled > a:hover,\n.navbar-inverse .navbar-nav > .disabled > a:focus {\n color: #444444;\n background-color: transparent;\n}\n.navbar-inverse .navbar-toggle {\n border-color: #333333;\n}\n.navbar-inverse .navbar-toggle:hover,\n.navbar-inverse .navbar-toggle:focus {\n background-color: #333333;\n}\n.navbar-inverse .navbar-toggle .icon-bar {\n background-color: #ffffff;\n}\n.navbar-inverse .navbar-collapse,\n.navbar-inverse .navbar-form {\n border-color: #101010;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .open > a:hover,\n.navbar-inverse .navbar-nav > .open > a:focus {\n background-color: #080808;\n color: #ffffff;\n}\n@media (max-width: 767px) {\n .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n border-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\n background-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n color: #9d9d9d;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\n color: #ffffff;\n background-color: transparent;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #ffffff;\n background-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n color: #444444;\n background-color: transparent;\n }\n}\n.navbar-inverse .navbar-link {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-link:hover {\n color: #ffffff;\n}\n.navbar-inverse .btn-link {\n color: #9d9d9d;\n}\n.navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link:focus {\n color: #ffffff;\n}\n.navbar-inverse .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-inverse .btn-link:focus {\n color: #444444;\n}\n.breadcrumb {\n padding: 8px 15px;\n margin-bottom: 20px;\n list-style: none;\n background-color: #f5f5f5;\n border-radius: 4px;\n}\n.breadcrumb > li {\n display: inline-block;\n}\n.breadcrumb > li + li:before {\n content: \"/\\00a0\";\n padding: 0 5px;\n color: #cccccc;\n}\n.breadcrumb > .active {\n color: #777777;\n}\n.pagination {\n display: inline-block;\n padding-left: 0;\n margin: 20px 0;\n border-radius: 4px;\n}\n.pagination > li {\n display: inline;\n}\n.pagination > li > a,\n.pagination > li > span {\n position: relative;\n float: left;\n padding: 6px 12px;\n line-height: 1.42857143;\n text-decoration: none;\n color: #428bca;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n margin-left: -1px;\n}\n.pagination > li:first-child > a,\n.pagination > li:first-child > span {\n margin-left: 0;\n border-bottom-left-radius: 4px;\n border-top-left-radius: 4px;\n}\n.pagination > li:last-child > a,\n.pagination > li:last-child > span {\n border-bottom-right-radius: 4px;\n border-top-right-radius: 4px;\n}\n.pagination > li > a:hover,\n.pagination > li > span:hover,\n.pagination > li > a:focus,\n.pagination > li > span:focus {\n color: #2a6496;\n background-color: #eeeeee;\n border-color: #dddddd;\n}\n.pagination > .active > a,\n.pagination > .active > span,\n.pagination > .active > a:hover,\n.pagination > .active > span:hover,\n.pagination > .active > a:focus,\n.pagination > .active > span:focus {\n z-index: 2;\n color: #ffffff;\n background-color: #428bca;\n border-color: #428bca;\n cursor: default;\n}\n.pagination > .disabled > span,\n.pagination > .disabled > span:hover,\n.pagination > .disabled > span:focus,\n.pagination > .disabled > a,\n.pagination > .disabled > a:hover,\n.pagination > .disabled > a:focus {\n color: #777777;\n background-color: #ffffff;\n border-color: #dddddd;\n cursor: not-allowed;\n}\n.pagination-lg > li > a,\n.pagination-lg > li > span {\n padding: 10px 16px;\n font-size: 18px;\n}\n.pagination-lg > li:first-child > a,\n.pagination-lg > li:first-child > span {\n border-bottom-left-radius: 6px;\n border-top-left-radius: 6px;\n}\n.pagination-lg > li:last-child > a,\n.pagination-lg > li:last-child > span {\n border-bottom-right-radius: 6px;\n border-top-right-radius: 6px;\n}\n.pagination-sm > li > a,\n.pagination-sm > li > span {\n padding: 5px 10px;\n font-size: 12px;\n}\n.pagination-sm > li:first-child > a,\n.pagination-sm > li:first-child > span {\n border-bottom-left-radius: 3px;\n border-top-left-radius: 3px;\n}\n.pagination-sm > li:last-child > a,\n.pagination-sm > li:last-child > span {\n border-bottom-right-radius: 3px;\n border-top-right-radius: 3px;\n}\n.pager {\n padding-left: 0;\n margin: 20px 0;\n list-style: none;\n text-align: center;\n}\n.pager li {\n display: inline;\n}\n.pager li > a,\n.pager li > span {\n display: inline-block;\n padding: 5px 14px;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n border-radius: 15px;\n}\n.pager li > a:hover,\n.pager li > a:focus {\n text-decoration: none;\n background-color: #eeeeee;\n}\n.pager .next > a,\n.pager .next > span {\n float: right;\n}\n.pager .previous > a,\n.pager .previous > span {\n float: left;\n}\n.pager .disabled > a,\n.pager .disabled > a:hover,\n.pager .disabled > a:focus,\n.pager .disabled > span {\n color: #777777;\n background-color: #ffffff;\n cursor: not-allowed;\n}\n.label {\n display: inline;\n padding: .2em .6em .3em;\n font-size: 75%;\n font-weight: bold;\n line-height: 1;\n color: #ffffff;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: .25em;\n}\na.label:hover,\na.label:focus {\n color: #ffffff;\n text-decoration: none;\n cursor: pointer;\n}\n.label:empty {\n display: none;\n}\n.btn .label {\n position: relative;\n top: -1px;\n}\n.label-default {\n background-color: #777777;\n}\n.label-default[href]:hover,\n.label-default[href]:focus {\n background-color: #5e5e5e;\n}\n.label-primary {\n background-color: #428bca;\n}\n.label-primary[href]:hover,\n.label-primary[href]:focus {\n background-color: #3071a9;\n}\n.label-success {\n background-color: #5cb85c;\n}\n.label-success[href]:hover,\n.label-success[href]:focus {\n background-color: #449d44;\n}\n.label-info {\n background-color: #5bc0de;\n}\n.label-info[href]:hover,\n.label-info[href]:focus {\n background-color: #31b0d5;\n}\n.label-warning {\n background-color: #f0ad4e;\n}\n.label-warning[href]:hover,\n.label-warning[href]:focus {\n background-color: #ec971f;\n}\n.label-danger {\n background-color: #d9534f;\n}\n.label-danger[href]:hover,\n.label-danger[href]:focus {\n background-color: #c9302c;\n}\n.badge {\n display: inline-block;\n min-width: 10px;\n padding: 3px 7px;\n font-size: 12px;\n font-weight: bold;\n color: #ffffff;\n line-height: 1;\n vertical-align: baseline;\n white-space: nowrap;\n text-align: center;\n background-color: #777777;\n border-radius: 10px;\n}\n.badge:empty {\n display: none;\n}\n.btn .badge {\n position: relative;\n top: -1px;\n}\n.btn-xs .badge {\n top: 0;\n padding: 1px 5px;\n}\na.badge:hover,\na.badge:focus {\n color: #ffffff;\n text-decoration: none;\n cursor: pointer;\n}\na.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n color: #428bca;\n background-color: #ffffff;\n}\n.nav-pills > li > a > .badge {\n margin-left: 3px;\n}\n.jumbotron {\n padding: 30px 15px;\n margin-bottom: 30px;\n color: inherit;\n background-color: #eeeeee;\n}\n.jumbotron h1,\n.jumbotron .h1 {\n color: inherit;\n}\n.jumbotron p {\n margin-bottom: 15px;\n font-size: 21px;\n font-weight: 200;\n}\n.jumbotron > hr {\n border-top-color: #d5d5d5;\n}\n.container .jumbotron,\n.container-fluid .jumbotron {\n border-radius: 6px;\n}\n.jumbotron .container {\n max-width: 100%;\n}\n@media screen and (min-width: 768px) {\n .jumbotron {\n padding: 48px 0;\n }\n .container .jumbotron {\n padding-left: 60px;\n padding-right: 60px;\n }\n .jumbotron h1,\n .jumbotron .h1 {\n font-size: 63px;\n }\n}\n.thumbnail {\n display: block;\n padding: 4px;\n margin-bottom: 20px;\n line-height: 1.42857143;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n border-radius: 4px;\n -webkit-transition: border 0.2s ease-in-out;\n -o-transition: border 0.2s ease-in-out;\n transition: border 0.2s ease-in-out;\n}\n.thumbnail > img,\n.thumbnail a > img {\n margin-left: auto;\n margin-right: auto;\n}\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n border-color: #428bca;\n}\n.thumbnail .caption {\n padding: 9px;\n color: #333333;\n}\n.alert {\n padding: 15px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.alert h4 {\n margin-top: 0;\n color: inherit;\n}\n.alert .alert-link {\n font-weight: bold;\n}\n.alert > p,\n.alert > ul {\n margin-bottom: 0;\n}\n.alert > p + p {\n margin-top: 5px;\n}\n.alert-dismissable,\n.alert-dismissible {\n padding-right: 35px;\n}\n.alert-dismissable .close,\n.alert-dismissible .close {\n position: relative;\n top: -2px;\n right: -21px;\n color: inherit;\n}\n.alert-success {\n background-color: #dff0d8;\n border-color: #d6e9c6;\n color: #3c763d;\n}\n.alert-success hr {\n border-top-color: #c9e2b3;\n}\n.alert-success .alert-link {\n color: #2b542c;\n}\n.alert-info {\n background-color: #d9edf7;\n border-color: #bce8f1;\n color: #31708f;\n}\n.alert-info hr {\n border-top-color: #a6e1ec;\n}\n.alert-info .alert-link {\n color: #245269;\n}\n.alert-warning {\n background-color: #fcf8e3;\n border-color: #faebcc;\n color: #8a6d3b;\n}\n.alert-warning hr {\n border-top-color: #f7e1b5;\n}\n.alert-warning .alert-link {\n color: #66512c;\n}\n.alert-danger {\n background-color: #f2dede;\n border-color: #ebccd1;\n color: #a94442;\n}\n.alert-danger hr {\n border-top-color: #e4b9c0;\n}\n.alert-danger .alert-link {\n color: #843534;\n}\n@-webkit-keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n@keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n.progress {\n overflow: hidden;\n height: 20px;\n margin-bottom: 20px;\n background-color: #f5f5f5;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n.progress-bar {\n float: left;\n width: 0%;\n height: 100%;\n font-size: 12px;\n line-height: 20px;\n color: #ffffff;\n text-align: center;\n background-color: #428bca;\n -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n -webkit-transition: width 0.6s ease;\n -o-transition: width 0.6s ease;\n transition: width 0.6s ease;\n}\n.progress-striped .progress-bar,\n.progress-bar-striped {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-size: 40px 40px;\n}\n.progress.active .progress-bar,\n.progress-bar.active {\n -webkit-animation: progress-bar-stripes 2s linear infinite;\n -o-animation: progress-bar-stripes 2s linear infinite;\n animation: progress-bar-stripes 2s linear infinite;\n}\n.progress-bar-success {\n background-color: #5cb85c;\n}\n.progress-striped .progress-bar-success {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-info {\n background-color: #5bc0de;\n}\n.progress-striped .progress-bar-info {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-warning {\n background-color: #f0ad4e;\n}\n.progress-striped .progress-bar-warning {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-danger {\n background-color: #d9534f;\n}\n.progress-striped .progress-bar-danger {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.media {\n margin-top: 15px;\n}\n.media:first-child {\n margin-top: 0;\n}\n.media-right,\n.media > .pull-right {\n padding-left: 10px;\n}\n.media-left,\n.media > .pull-left {\n padding-right: 10px;\n}\n.media-left,\n.media-right,\n.media-body {\n display: table-cell;\n vertical-align: top;\n}\n.media-middle {\n vertical-align: middle;\n}\n.media-bottom {\n vertical-align: bottom;\n}\n.media-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.media-list {\n padding-left: 0;\n list-style: none;\n}\n.list-group {\n margin-bottom: 20px;\n padding-left: 0;\n}\n.list-group-item {\n position: relative;\n display: block;\n padding: 10px 15px;\n margin-bottom: -1px;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n}\n.list-group-item:first-child {\n border-top-right-radius: 4px;\n border-top-left-radius: 4px;\n}\n.list-group-item:last-child {\n margin-bottom: 0;\n border-bottom-right-radius: 4px;\n border-bottom-left-radius: 4px;\n}\n.list-group-item > .badge {\n float: right;\n}\n.list-group-item > .badge + .badge {\n margin-right: 5px;\n}\na.list-group-item {\n color: #555555;\n}\na.list-group-item .list-group-item-heading {\n color: #333333;\n}\na.list-group-item:hover,\na.list-group-item:focus {\n text-decoration: none;\n color: #555555;\n background-color: #f5f5f5;\n}\n.list-group-item.disabled,\n.list-group-item.disabled:hover,\n.list-group-item.disabled:focus {\n background-color: #eeeeee;\n color: #777777;\n cursor: not-allowed;\n}\n.list-group-item.disabled .list-group-item-heading,\n.list-group-item.disabled:hover .list-group-item-heading,\n.list-group-item.disabled:focus .list-group-item-heading {\n color: inherit;\n}\n.list-group-item.disabled .list-group-item-text,\n.list-group-item.disabled:hover .list-group-item-text,\n.list-group-item.disabled:focus .list-group-item-text {\n color: #777777;\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n z-index: 2;\n color: #ffffff;\n background-color: #428bca;\n border-color: #428bca;\n}\n.list-group-item.active .list-group-item-heading,\n.list-group-item.active:hover .list-group-item-heading,\n.list-group-item.active:focus .list-group-item-heading,\n.list-group-item.active .list-group-item-heading > small,\n.list-group-item.active:hover .list-group-item-heading > small,\n.list-group-item.active:focus .list-group-item-heading > small,\n.list-group-item.active .list-group-item-heading > .small,\n.list-group-item.active:hover .list-group-item-heading > .small,\n.list-group-item.active:focus .list-group-item-heading > .small {\n color: inherit;\n}\n.list-group-item.active .list-group-item-text,\n.list-group-item.active:hover .list-group-item-text,\n.list-group-item.active:focus .list-group-item-text {\n color: #e1edf7;\n}\n.list-group-item-success {\n color: #3c763d;\n background-color: #dff0d8;\n}\na.list-group-item-success {\n color: #3c763d;\n}\na.list-group-item-success .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-success:hover,\na.list-group-item-success:focus {\n color: #3c763d;\n background-color: #d0e9c6;\n}\na.list-group-item-success.active,\na.list-group-item-success.active:hover,\na.list-group-item-success.active:focus {\n color: #fff;\n background-color: #3c763d;\n border-color: #3c763d;\n}\n.list-group-item-info {\n color: #31708f;\n background-color: #d9edf7;\n}\na.list-group-item-info {\n color: #31708f;\n}\na.list-group-item-info .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-info:hover,\na.list-group-item-info:focus {\n color: #31708f;\n background-color: #c4e3f3;\n}\na.list-group-item-info.active,\na.list-group-item-info.active:hover,\na.list-group-item-info.active:focus {\n color: #fff;\n background-color: #31708f;\n border-color: #31708f;\n}\n.list-group-item-warning {\n color: #8a6d3b;\n background-color: #fcf8e3;\n}\na.list-group-item-warning {\n color: #8a6d3b;\n}\na.list-group-item-warning .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-warning:hover,\na.list-group-item-warning:focus {\n color: #8a6d3b;\n background-color: #faf2cc;\n}\na.list-group-item-warning.active,\na.list-group-item-warning.active:hover,\na.list-group-item-warning.active:focus {\n color: #fff;\n background-color: #8a6d3b;\n border-color: #8a6d3b;\n}\n.list-group-item-danger {\n color: #a94442;\n background-color: #f2dede;\n}\na.list-group-item-danger {\n color: #a94442;\n}\na.list-group-item-danger .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-danger:hover,\na.list-group-item-danger:focus {\n color: #a94442;\n background-color: #ebcccc;\n}\na.list-group-item-danger.active,\na.list-group-item-danger.active:hover,\na.list-group-item-danger.active:focus {\n color: #fff;\n background-color: #a94442;\n border-color: #a94442;\n}\n.list-group-item-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.list-group-item-text {\n margin-bottom: 0;\n line-height: 1.3;\n}\n.panel {\n margin-bottom: 20px;\n background-color: #ffffff;\n border: 1px solid transparent;\n border-radius: 4px;\n -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.panel-body {\n padding: 15px;\n}\n.panel-heading {\n padding: 10px 15px;\n border-bottom: 1px solid transparent;\n border-top-right-radius: 3px;\n border-top-left-radius: 3px;\n}\n.panel-heading > .dropdown .dropdown-toggle {\n color: inherit;\n}\n.panel-title {\n margin-top: 0;\n margin-bottom: 0;\n font-size: 16px;\n color: inherit;\n}\n.panel-title > a {\n color: inherit;\n}\n.panel-footer {\n padding: 10px 15px;\n background-color: #f5f5f5;\n border-top: 1px solid #dddddd;\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .list-group,\n.panel > .panel-collapse > .list-group {\n margin-bottom: 0;\n}\n.panel > .list-group .list-group-item,\n.panel > .panel-collapse > .list-group .list-group-item {\n border-width: 1px 0;\n border-radius: 0;\n}\n.panel > .list-group:first-child .list-group-item:first-child,\n.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {\n border-top: 0;\n border-top-right-radius: 3px;\n border-top-left-radius: 3px;\n}\n.panel > .list-group:last-child .list-group-item:last-child,\n.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {\n border-bottom: 0;\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel-heading + .list-group .list-group-item:first-child {\n border-top-width: 0;\n}\n.list-group + .panel-footer {\n border-top-width: 0;\n}\n.panel > .table,\n.panel > .table-responsive > .table,\n.panel > .panel-collapse > .table {\n margin-bottom: 0;\n}\n.panel > .table caption,\n.panel > .table-responsive > .table caption,\n.panel > .panel-collapse > .table caption {\n padding-left: 15px;\n padding-right: 15px;\n}\n.panel > .table:first-child,\n.panel > .table-responsive:first-child > .table:first-child {\n border-top-right-radius: 3px;\n border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {\n border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {\n border-top-right-radius: 3px;\n}\n.panel > .table:last-child,\n.panel > .table-responsive:last-child > .table:last-child {\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {\n border-bottom-left-radius: 3px;\n border-bottom-right-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {\n border-bottom-right-radius: 3px;\n}\n.panel > .panel-body + .table,\n.panel > .panel-body + .table-responsive,\n.panel > .table + .panel-body,\n.panel > .table-responsive + .panel-body {\n border-top: 1px solid #dddddd;\n}\n.panel > .table > tbody:first-child > tr:first-child th,\n.panel > .table > tbody:first-child > tr:first-child td {\n border-top: 0;\n}\n.panel > .table-bordered,\n.panel > .table-responsive > .table-bordered {\n border: 0;\n}\n.panel > .table-bordered > thead > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\n.panel > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-bordered > thead > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\n.panel > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-bordered > tfoot > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n border-left: 0;\n}\n.panel > .table-bordered > thead > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\n.panel > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-bordered > thead > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\n.panel > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-bordered > tfoot > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n border-right: 0;\n}\n.panel > .table-bordered > thead > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,\n.panel > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-bordered > thead > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,\n.panel > .table-bordered > tbody > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {\n border-bottom: 0;\n}\n.panel > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-bordered > tfoot > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {\n border-bottom: 0;\n}\n.panel > .table-responsive {\n border: 0;\n margin-bottom: 0;\n}\n.panel-group {\n margin-bottom: 20px;\n}\n.panel-group .panel {\n margin-bottom: 0;\n border-radius: 4px;\n}\n.panel-group .panel + .panel {\n margin-top: 5px;\n}\n.panel-group .panel-heading {\n border-bottom: 0;\n}\n.panel-group .panel-heading + .panel-collapse > .panel-body,\n.panel-group .panel-heading + .panel-collapse > .list-group {\n border-top: 1px solid #dddddd;\n}\n.panel-group .panel-footer {\n border-top: 0;\n}\n.panel-group .panel-footer + .panel-collapse .panel-body {\n border-bottom: 1px solid #dddddd;\n}\n.panel-default {\n border-color: #dddddd;\n}\n.panel-default > .panel-heading {\n color: #333333;\n background-color: #f5f5f5;\n border-color: #dddddd;\n}\n.panel-default > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #dddddd;\n}\n.panel-default > .panel-heading .badge {\n color: #f5f5f5;\n background-color: #333333;\n}\n.panel-default > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #dddddd;\n}\n.panel-primary {\n border-color: #428bca;\n}\n.panel-primary > .panel-heading {\n color: #ffffff;\n background-color: #428bca;\n border-color: #428bca;\n}\n.panel-primary > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #428bca;\n}\n.panel-primary > .panel-heading .badge {\n color: #428bca;\n background-color: #ffffff;\n}\n.panel-primary > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #428bca;\n}\n.panel-success {\n border-color: #d6e9c6;\n}\n.panel-success > .panel-heading {\n color: #3c763d;\n background-color: #dff0d8;\n border-color: #d6e9c6;\n}\n.panel-success > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #d6e9c6;\n}\n.panel-success > .panel-heading .badge {\n color: #dff0d8;\n background-color: #3c763d;\n}\n.panel-success > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #d6e9c6;\n}\n.panel-info {\n border-color: #bce8f1;\n}\n.panel-info > .panel-heading {\n color: #31708f;\n background-color: #d9edf7;\n border-color: #bce8f1;\n}\n.panel-info > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #bce8f1;\n}\n.panel-info > .panel-heading .badge {\n color: #d9edf7;\n background-color: #31708f;\n}\n.panel-info > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #bce8f1;\n}\n.panel-warning {\n border-color: #faebcc;\n}\n.panel-warning > .panel-heading {\n color: #8a6d3b;\n background-color: #fcf8e3;\n border-color: #faebcc;\n}\n.panel-warning > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #faebcc;\n}\n.panel-warning > .panel-heading .badge {\n color: #fcf8e3;\n background-color: #8a6d3b;\n}\n.panel-warning > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #faebcc;\n}\n.panel-danger {\n border-color: #ebccd1;\n}\n.panel-danger > .panel-heading {\n color: #a94442;\n background-color: #f2dede;\n border-color: #ebccd1;\n}\n.panel-danger > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #ebccd1;\n}\n.panel-danger > .panel-heading .badge {\n color: #f2dede;\n background-color: #a94442;\n}\n.panel-danger > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #ebccd1;\n}\n.embed-responsive {\n position: relative;\n display: block;\n height: 0;\n padding: 0;\n overflow: hidden;\n}\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object,\n.embed-responsive video {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n height: 100%;\n width: 100%;\n border: 0;\n}\n.embed-responsive.embed-responsive-16by9 {\n padding-bottom: 56.25%;\n}\n.embed-responsive.embed-responsive-4by3 {\n padding-bottom: 75%;\n}\n.well {\n min-height: 20px;\n padding: 19px;\n margin-bottom: 20px;\n background-color: #f5f5f5;\n border: 1px solid #e3e3e3;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.well blockquote {\n border-color: #ddd;\n border-color: rgba(0, 0, 0, 0.15);\n}\n.well-lg {\n padding: 24px;\n border-radius: 6px;\n}\n.well-sm {\n padding: 9px;\n border-radius: 3px;\n}\n.close {\n float: right;\n font-size: 21px;\n font-weight: bold;\n line-height: 1;\n color: #000000;\n text-shadow: 0 1px 0 #ffffff;\n opacity: 0.2;\n filter: alpha(opacity=20);\n}\n.close:hover,\n.close:focus {\n color: #000000;\n text-decoration: none;\n cursor: pointer;\n opacity: 0.5;\n filter: alpha(opacity=50);\n}\nbutton.close {\n padding: 0;\n cursor: pointer;\n background: transparent;\n border: 0;\n -webkit-appearance: none;\n}\n.modal-open {\n overflow: hidden;\n}\n.modal {\n display: none;\n overflow: hidden;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1040;\n -webkit-overflow-scrolling: touch;\n outline: 0;\n}\n.modal.fade .modal-dialog {\n -webkit-transform: translate(0, -25%);\n -ms-transform: translate(0, -25%);\n -o-transform: translate(0, -25%);\n transform: translate(0, -25%);\n -webkit-transition: -webkit-transform 0.3s ease-out;\n -moz-transition: -moz-transform 0.3s ease-out;\n -o-transition: -o-transform 0.3s ease-out;\n transition: transform 0.3s ease-out;\n}\n.modal.in .modal-dialog {\n -webkit-transform: translate(0, 0);\n -ms-transform: translate(0, 0);\n -o-transform: translate(0, 0);\n transform: translate(0, 0);\n}\n.modal-open .modal {\n overflow-x: hidden;\n overflow-y: auto;\n}\n.modal-dialog {\n position: relative;\n width: auto;\n margin: 10px;\n}\n.modal-content {\n position: relative;\n background-color: #ffffff;\n border: 1px solid #999999;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 6px;\n -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n background-clip: padding-box;\n outline: 0;\n}\n.modal-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n background-color: #000000;\n}\n.modal-backdrop.fade {\n opacity: 0;\n filter: alpha(opacity=0);\n}\n.modal-backdrop.in {\n opacity: 0.5;\n filter: alpha(opacity=50);\n}\n.modal-header {\n padding: 15px;\n border-bottom: 1px solid #e5e5e5;\n min-height: 16.42857143px;\n}\n.modal-header .close {\n margin-top: -2px;\n}\n.modal-title {\n margin: 0;\n line-height: 1.42857143;\n}\n.modal-body {\n position: relative;\n padding: 15px;\n}\n.modal-footer {\n padding: 15px;\n text-align: right;\n border-top: 1px solid #e5e5e5;\n}\n.modal-footer .btn + .btn {\n margin-left: 5px;\n margin-bottom: 0;\n}\n.modal-footer .btn-group .btn + .btn {\n margin-left: -1px;\n}\n.modal-footer .btn-block + .btn-block {\n margin-left: 0;\n}\n.modal-scrollbar-measure {\n position: absolute;\n top: -9999px;\n width: 50px;\n height: 50px;\n overflow: scroll;\n}\n@media (min-width: 768px) {\n .modal-dialog {\n width: 600px;\n margin: 30px auto;\n }\n .modal-content {\n -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n }\n .modal-sm {\n width: 300px;\n }\n}\n@media (min-width: 992px) {\n .modal-lg {\n width: 900px;\n }\n}\n.tooltip {\n position: absolute;\n z-index: 1070;\n display: block;\n visibility: visible;\n font-size: 12px;\n line-height: 1.4;\n opacity: 0;\n filter: alpha(opacity=0);\n}\n.tooltip.in {\n opacity: 0.9;\n filter: alpha(opacity=90);\n}\n.tooltip.top {\n margin-top: -3px;\n padding: 5px 0;\n}\n.tooltip.right {\n margin-left: 3px;\n padding: 0 5px;\n}\n.tooltip.bottom {\n margin-top: 3px;\n padding: 5px 0;\n}\n.tooltip.left {\n margin-left: -3px;\n padding: 0 5px;\n}\n.tooltip-inner {\n max-width: 200px;\n padding: 3px 8px;\n color: #ffffff;\n text-align: center;\n text-decoration: none;\n background-color: #000000;\n border-radius: 4px;\n}\n.tooltip-arrow {\n position: absolute;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.tooltip.top .tooltip-arrow {\n bottom: 0;\n left: 50%;\n margin-left: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000000;\n}\n.tooltip.top-left .tooltip-arrow {\n bottom: 0;\n left: 5px;\n border-width: 5px 5px 0;\n border-top-color: #000000;\n}\n.tooltip.top-right .tooltip-arrow {\n bottom: 0;\n right: 5px;\n border-width: 5px 5px 0;\n border-top-color: #000000;\n}\n.tooltip.right .tooltip-arrow {\n top: 50%;\n left: 0;\n margin-top: -5px;\n border-width: 5px 5px 5px 0;\n border-right-color: #000000;\n}\n.tooltip.left .tooltip-arrow {\n top: 50%;\n right: 0;\n margin-top: -5px;\n border-width: 5px 0 5px 5px;\n border-left-color: #000000;\n}\n.tooltip.bottom .tooltip-arrow {\n top: 0;\n left: 50%;\n margin-left: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000000;\n}\n.tooltip.bottom-left .tooltip-arrow {\n top: 0;\n left: 5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000000;\n}\n.tooltip.bottom-right .tooltip-arrow {\n top: 0;\n right: 5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000000;\n}\n.popover {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 1060;\n display: none;\n max-width: 276px;\n padding: 1px;\n font-size: 14px;\n font-weight: normal;\n line-height: 1.42857143;\n text-align: left;\n background-color: #ffffff;\n background-clip: padding-box;\n border: 1px solid #cccccc;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 6px;\n -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n white-space: normal;\n}\n.popover.top {\n margin-top: -10px;\n}\n.popover.right {\n margin-left: 10px;\n}\n.popover.bottom {\n margin-top: 10px;\n}\n.popover.left {\n margin-left: -10px;\n}\n.popover-title {\n margin: 0;\n padding: 8px 14px;\n font-size: 14px;\n background-color: #f7f7f7;\n border-bottom: 1px solid #ebebeb;\n border-radius: 5px 5px 0 0;\n}\n.popover-content {\n padding: 9px 14px;\n}\n.popover > .arrow,\n.popover > .arrow:after {\n position: absolute;\n display: block;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.popover > .arrow {\n border-width: 11px;\n}\n.popover > .arrow:after {\n border-width: 10px;\n content: \"\";\n}\n.popover.top > .arrow {\n left: 50%;\n margin-left: -11px;\n border-bottom-width: 0;\n border-top-color: #999999;\n border-top-color: rgba(0, 0, 0, 0.25);\n bottom: -11px;\n}\n.popover.top > .arrow:after {\n content: \" \";\n bottom: 1px;\n margin-left: -10px;\n border-bottom-width: 0;\n border-top-color: #ffffff;\n}\n.popover.right > .arrow {\n top: 50%;\n left: -11px;\n margin-top: -11px;\n border-left-width: 0;\n border-right-color: #999999;\n border-right-color: rgba(0, 0, 0, 0.25);\n}\n.popover.right > .arrow:after {\n content: \" \";\n left: 1px;\n bottom: -10px;\n border-left-width: 0;\n border-right-color: #ffffff;\n}\n.popover.bottom > .arrow {\n left: 50%;\n margin-left: -11px;\n border-top-width: 0;\n border-bottom-color: #999999;\n border-bottom-color: rgba(0, 0, 0, 0.25);\n top: -11px;\n}\n.popover.bottom > .arrow:after {\n content: \" \";\n top: 1px;\n margin-left: -10px;\n border-top-width: 0;\n border-bottom-color: #ffffff;\n}\n.popover.left > .arrow {\n top: 50%;\n right: -11px;\n margin-top: -11px;\n border-right-width: 0;\n border-left-color: #999999;\n border-left-color: rgba(0, 0, 0, 0.25);\n}\n.popover.left > .arrow:after {\n content: \" \";\n right: 1px;\n border-right-width: 0;\n border-left-color: #ffffff;\n bottom: -10px;\n}\n.carousel {\n position: relative;\n}\n.carousel-inner {\n position: relative;\n overflow: hidden;\n width: 100%;\n}\n.carousel-inner > .item {\n display: none;\n position: relative;\n -webkit-transition: 0.6s ease-in-out left;\n -o-transition: 0.6s ease-in-out left;\n transition: 0.6s ease-in-out left;\n}\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n line-height: 1;\n}\n@media all and (transform-3d), (-webkit-transform-3d) {\n .carousel-inner > .item {\n transition: transform 0.6s ease-in-out;\n backface-visibility: hidden;\n perspective: 1000;\n }\n .carousel-inner > .item.next,\n .carousel-inner > .item.active.right {\n transform: translate3d(100%, 0, 0);\n left: 0;\n }\n .carousel-inner > .item.prev,\n .carousel-inner > .item.active.left {\n transform: translate3d(-100%, 0, 0);\n left: 0;\n }\n .carousel-inner > .item.next.left,\n .carousel-inner > .item.prev.right,\n .carousel-inner > .item.active {\n transform: translate3d(0, 0, 0);\n left: 0;\n }\n}\n.carousel-inner > .active,\n.carousel-inner > .next,\n.carousel-inner > .prev {\n display: block;\n}\n.carousel-inner > .active {\n left: 0;\n}\n.carousel-inner > .next,\n.carousel-inner > .prev {\n position: absolute;\n top: 0;\n width: 100%;\n}\n.carousel-inner > .next {\n left: 100%;\n}\n.carousel-inner > .prev {\n left: -100%;\n}\n.carousel-inner > .next.left,\n.carousel-inner > .prev.right {\n left: 0;\n}\n.carousel-inner > .active.left {\n left: -100%;\n}\n.carousel-inner > .active.right {\n left: 100%;\n}\n.carousel-control {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n width: 15%;\n opacity: 0.5;\n filter: alpha(opacity=50);\n font-size: 20px;\n color: #ffffff;\n text-align: center;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-control.left {\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n}\n.carousel-control.right {\n left: auto;\n right: 0;\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n}\n.carousel-control:hover,\n.carousel-control:focus {\n outline: 0;\n color: #ffffff;\n text-decoration: none;\n opacity: 0.9;\n filter: alpha(opacity=90);\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-left,\n.carousel-control .glyphicon-chevron-right {\n position: absolute;\n top: 50%;\n z-index: 5;\n display: inline-block;\n}\n.carousel-control .icon-prev,\n.carousel-control .glyphicon-chevron-left {\n left: 50%;\n margin-left: -10px;\n}\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-right {\n right: 50%;\n margin-right: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next {\n width: 20px;\n height: 20px;\n margin-top: -10px;\n font-family: serif;\n}\n.carousel-control .icon-prev:before {\n content: '\\2039';\n}\n.carousel-control .icon-next:before {\n content: '\\203a';\n}\n.carousel-indicators {\n position: absolute;\n bottom: 10px;\n left: 50%;\n z-index: 15;\n width: 60%;\n margin-left: -30%;\n padding-left: 0;\n list-style: none;\n text-align: center;\n}\n.carousel-indicators li {\n display: inline-block;\n width: 10px;\n height: 10px;\n margin: 1px;\n text-indent: -999px;\n border: 1px solid #ffffff;\n border-radius: 10px;\n cursor: pointer;\n background-color: #000 \\9;\n background-color: rgba(0, 0, 0, 0);\n}\n.carousel-indicators .active {\n margin: 0;\n width: 12px;\n height: 12px;\n background-color: #ffffff;\n}\n.carousel-caption {\n position: absolute;\n left: 15%;\n right: 15%;\n bottom: 20px;\n z-index: 10;\n padding-top: 20px;\n padding-bottom: 20px;\n color: #ffffff;\n text-align: center;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-caption .btn {\n text-shadow: none;\n}\n@media screen and (min-width: 768px) {\n .carousel-control .glyphicon-chevron-left,\n .carousel-control .glyphicon-chevron-right,\n .carousel-control .icon-prev,\n .carousel-control .icon-next {\n width: 30px;\n height: 30px;\n margin-top: -15px;\n font-size: 30px;\n }\n .carousel-control .glyphicon-chevron-left,\n .carousel-control .icon-prev {\n margin-left: -15px;\n }\n .carousel-control .glyphicon-chevron-right,\n .carousel-control .icon-next {\n margin-right: -15px;\n }\n .carousel-caption {\n left: 20%;\n right: 20%;\n padding-bottom: 30px;\n }\n .carousel-indicators {\n bottom: 20px;\n }\n}\n.clearfix:before,\n.clearfix:after,\n.dl-horizontal dd:before,\n.dl-horizontal dd:after,\n.container:before,\n.container:after,\n.container-fluid:before,\n.container-fluid:after,\n.row:before,\n.row:after,\n.form-horizontal .form-group:before,\n.form-horizontal .form-group:after,\n.btn-toolbar:before,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:before,\n.btn-group-vertical > .btn-group:after,\n.nav:before,\n.nav:after,\n.navbar:before,\n.navbar:after,\n.navbar-header:before,\n.navbar-header:after,\n.navbar-collapse:before,\n.navbar-collapse:after,\n.pager:before,\n.pager:after,\n.panel-body:before,\n.panel-body:after,\n.modal-footer:before,\n.modal-footer:after {\n content: \" \";\n display: table;\n}\n.clearfix:after,\n.dl-horizontal dd:after,\n.container:after,\n.container-fluid:after,\n.row:after,\n.form-horizontal .form-group:after,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:after,\n.nav:after,\n.navbar:after,\n.navbar-header:after,\n.navbar-collapse:after,\n.pager:after,\n.panel-body:after,\n.modal-footer:after {\n clear: both;\n}\n.center-block {\n display: block;\n margin-left: auto;\n margin-right: auto;\n}\n.pull-right {\n float: right !important;\n}\n.pull-left {\n float: left !important;\n}\n.hide {\n display: none !important;\n}\n.show {\n display: block !important;\n}\n.invisible {\n visibility: hidden;\n}\n.text-hide {\n font: 0/0 a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n.hidden {\n display: none !important;\n visibility: hidden !important;\n}\n.affix {\n position: fixed;\n}\n@-ms-viewport {\n width: device-width;\n}\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n display: none !important;\n}\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n display: none !important;\n}\n@media (max-width: 767px) {\n .visible-xs {\n display: block !important;\n }\n table.visible-xs {\n display: table;\n }\n tr.visible-xs {\n display: table-row !important;\n }\n th.visible-xs,\n td.visible-xs {\n display: table-cell !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-block {\n display: block !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-inline {\n display: inline !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm {\n display: block !important;\n }\n table.visible-sm {\n display: table;\n }\n tr.visible-sm {\n display: table-row !important;\n }\n th.visible-sm,\n td.visible-sm {\n display: table-cell !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-block {\n display: block !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-inline {\n display: inline !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md {\n display: block !important;\n }\n table.visible-md {\n display: table;\n }\n tr.visible-md {\n display: table-row !important;\n }\n th.visible-md,\n td.visible-md {\n display: table-cell !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-block {\n display: block !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-inline {\n display: inline !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg {\n display: block !important;\n }\n table.visible-lg {\n display: table;\n }\n tr.visible-lg {\n display: table-row !important;\n }\n th.visible-lg,\n td.visible-lg {\n display: table-cell !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-block {\n display: block !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-inline {\n display: inline !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-inline-block {\n display: inline-block !important;\n }\n}\n@media (max-width: 767px) {\n .hidden-xs {\n display: none !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .hidden-sm {\n display: none !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .hidden-md {\n display: none !important;\n }\n}\n@media (min-width: 1200px) {\n .hidden-lg {\n display: none !important;\n }\n}\n.visible-print {\n display: none !important;\n}\n@media print {\n .visible-print {\n display: block !important;\n }\n table.visible-print {\n display: table;\n }\n tr.visible-print {\n display: table-row !important;\n }\n th.visible-print,\n td.visible-print {\n display: table-cell !important;\n }\n}\n.visible-print-block {\n display: none !important;\n}\n@media print {\n .visible-print-block {\n display: block !important;\n }\n}\n.visible-print-inline {\n display: none !important;\n}\n@media print {\n .visible-print-inline {\n display: inline !important;\n }\n}\n.visible-print-inline-block {\n display: none !important;\n}\n@media print {\n .visible-print-inline-block {\n display: inline-block !important;\n }\n}\n@media print {\n .hidden-print {\n display: none !important;\n }\n}\n/*# sourceMappingURL=bootstrap.css.map */","/*! normalize.css v3.0.2 | MIT License | git.io/normalize */\n\n//\n// 1. Set default font family to sans-serif.\n// 2. Prevent iOS text size adjust after orientation change, without disabling\n// user zoom.\n//\n\nhtml {\n font-family: sans-serif; // 1\n -ms-text-size-adjust: 100%; // 2\n -webkit-text-size-adjust: 100%; // 2\n}\n\n//\n// Remove default margin.\n//\n\nbody {\n margin: 0;\n}\n\n// HTML5 display definitions\n// ==========================================================================\n\n//\n// Correct `block` display not defined for any HTML5 element in IE 8/9.\n// Correct `block` display not defined for `details` or `summary` in IE 10/11\n// and Firefox.\n// Correct `block` display not defined for `main` in IE 11.\n//\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n display: block;\n}\n\n//\n// 1. Correct `inline-block` display not defined in IE 8/9.\n// 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.\n//\n\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block; // 1\n vertical-align: baseline; // 2\n}\n\n//\n// Prevent modern browsers from displaying `audio` without controls.\n// Remove excess height in iOS 5 devices.\n//\n\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n\n//\n// Address `[hidden]` styling not present in IE 8/9/10.\n// Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.\n//\n\n[hidden],\ntemplate {\n display: none;\n}\n\n// Links\n// ==========================================================================\n\n//\n// Remove the gray background color from active links in IE 10.\n//\n\na {\n background-color: transparent;\n}\n\n//\n// Improve readability when focused and also mouse hovered in all browsers.\n//\n\na:active,\na:hover {\n outline: 0;\n}\n\n// Text-level semantics\n// ==========================================================================\n\n//\n// Address styling not present in IE 8/9/10/11, Safari, and Chrome.\n//\n\nabbr[title] {\n border-bottom: 1px dotted;\n}\n\n//\n// Address style set to `bolder` in Firefox 4+, Safari, and Chrome.\n//\n\nb,\nstrong {\n font-weight: bold;\n}\n\n//\n// Address styling not present in Safari and Chrome.\n//\n\ndfn {\n font-style: italic;\n}\n\n//\n// Address variable `h1` font-size and margin within `section` and `article`\n// contexts in Firefox 4+, Safari, and Chrome.\n//\n\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\n\n//\n// Address styling not present in IE 8/9.\n//\n\nmark {\n background: #ff0;\n color: #000;\n}\n\n//\n// Address inconsistent and variable font size in all browsers.\n//\n\nsmall {\n font-size: 80%;\n}\n\n//\n// Prevent `sub` and `sup` affecting `line-height` in all browsers.\n//\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsup {\n top: -0.5em;\n}\n\nsub {\n bottom: -0.25em;\n}\n\n// Embedded content\n// ==========================================================================\n\n//\n// Remove border when inside `a` element in IE 8/9/10.\n//\n\nimg {\n border: 0;\n}\n\n//\n// Correct overflow not hidden in IE 9/10/11.\n//\n\nsvg:not(:root) {\n overflow: hidden;\n}\n\n// Grouping content\n// ==========================================================================\n\n//\n// Address margin not present in IE 8/9 and Safari.\n//\n\nfigure {\n margin: 1em 40px;\n}\n\n//\n// Address differences between Firefox and other browsers.\n//\n\nhr {\n -moz-box-sizing: content-box;\n box-sizing: content-box;\n height: 0;\n}\n\n//\n// Contain overflow in all browsers.\n//\n\npre {\n overflow: auto;\n}\n\n//\n// Address odd `em`-unit font size rendering in all browsers.\n//\n\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\n\n// Forms\n// ==========================================================================\n\n//\n// Known limitation: by default, Chrome and Safari on OS X allow very limited\n// styling of `select`, unless a `border` property is set.\n//\n\n//\n// 1. Correct color not being inherited.\n// Known issue: affects color of disabled elements.\n// 2. Correct font properties not being inherited.\n// 3. Address margins set differently in Firefox 4+, Safari, and Chrome.\n//\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n color: inherit; // 1\n font: inherit; // 2\n margin: 0; // 3\n}\n\n//\n// Address `overflow` set to `hidden` in IE 8/9/10/11.\n//\n\nbutton {\n overflow: visible;\n}\n\n//\n// Address inconsistent `text-transform` inheritance for `button` and `select`.\n// All other form control elements do not inherit `text-transform` values.\n// Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.\n// Correct `select` style inheritance in Firefox.\n//\n\nbutton,\nselect {\n text-transform: none;\n}\n\n//\n// 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\n// and `video` controls.\n// 2. Correct inability to style clickable `input` types in iOS.\n// 3. Improve usability and consistency of cursor style between image-type\n// `input` and others.\n//\n\nbutton,\nhtml input[type=\"button\"], // 1\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button; // 2\n cursor: pointer; // 3\n}\n\n//\n// Re-set default cursor for disabled elements.\n//\n\nbutton[disabled],\nhtml input[disabled] {\n cursor: default;\n}\n\n//\n// Remove inner padding and border in Firefox 4+.\n//\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0;\n}\n\n//\n// Address Firefox 4+ setting `line-height` on `input` using `!important` in\n// the UA stylesheet.\n//\n\ninput {\n line-height: normal;\n}\n\n//\n// It's recommended that you don't attempt to style these elements.\n// Firefox's implementation doesn't respect box-sizing, padding, or width.\n//\n// 1. Address box sizing set to `content-box` in IE 8/9/10.\n// 2. Remove excess padding in IE 8/9/10.\n//\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n box-sizing: border-box; // 1\n padding: 0; // 2\n}\n\n//\n// Fix the cursor style for Chrome's increment/decrement buttons. For certain\n// `font-size` values of the `input`, it causes the cursor style of the\n// decrement button to change from `default` to `text`.\n//\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n//\n// 1. Address `appearance` set to `searchfield` in Safari and Chrome.\n// 2. Address `box-sizing` set to `border-box` in Safari and Chrome\n// (include `-moz` to future-proof).\n//\n\ninput[type=\"search\"] {\n -webkit-appearance: textfield; // 1\n -moz-box-sizing: content-box;\n -webkit-box-sizing: content-box; // 2\n box-sizing: content-box;\n}\n\n//\n// Remove inner padding and search cancel button in Safari and Chrome on OS X.\n// Safari (but not Chrome) clips the cancel button when the search input has\n// padding (and `textfield` appearance).\n//\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n//\n// Define consistent border, margin, and padding.\n//\n\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: 0.35em 0.625em 0.75em;\n}\n\n//\n// 1. Correct `color` not being inherited in IE 8/9/10/11.\n// 2. Remove padding so people aren't caught out if they zero out fieldsets.\n//\n\nlegend {\n border: 0; // 1\n padding: 0; // 2\n}\n\n//\n// Remove default vertical scrollbar in IE 8/9/10/11.\n//\n\ntextarea {\n overflow: auto;\n}\n\n//\n// Don't inherit the `font-weight` (applied by a rule above).\n// NOTE: the default cannot safely be changed in Chrome and Safari on OS X.\n//\n\noptgroup {\n font-weight: bold;\n}\n\n// Tables\n// ==========================================================================\n\n//\n// Remove most spacing between table cells.\n//\n\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n}\n\ntd,\nth {\n padding: 0;\n}\n","/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n\n// ==========================================================================\n// Print styles.\n// Inlined to avoid the additional HTTP request: h5bp.com/r\n// ==========================================================================\n\n@media print {\n *,\n *:before,\n *:after {\n background: transparent !important;\n color: #000 !important; // Black prints faster: h5bp.com/s\n box-shadow: none !important;\n text-shadow: none !important;\n }\n\n a,\n a:visited {\n text-decoration: underline;\n }\n\n a[href]:after {\n content: \" (\" attr(href) \")\";\n }\n\n abbr[title]:after {\n content: \" (\" attr(title) \")\";\n }\n\n // Don't show links that are fragment identifiers,\n // or use the `javascript:` pseudo protocol\n a[href^=\"#\"]:after,\n a[href^=\"javascript:\"]:after {\n content: \"\";\n }\n\n pre,\n blockquote {\n border: 1px solid #999;\n page-break-inside: avoid;\n }\n\n thead {\n display: table-header-group; // h5bp.com/t\n }\n\n tr,\n img {\n page-break-inside: avoid;\n }\n\n img {\n max-width: 100% !important;\n }\n\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n\n h2,\n h3 {\n page-break-after: avoid;\n }\n\n // Bootstrap specific changes start\n //\n // Chrome (OSX) fix for https://github.com/twbs/bootstrap/issues/11245\n // Once fixed, we can just straight up remove this.\n select {\n background: #fff !important;\n }\n\n // Bootstrap components\n .navbar {\n display: none;\n }\n .btn,\n .dropup > .btn {\n > .caret {\n border-top-color: #000 !important;\n }\n }\n .label {\n border: 1px solid #000;\n }\n\n .table {\n border-collapse: collapse !important;\n\n td,\n th {\n background-color: #fff !important;\n }\n }\n .table-bordered {\n th,\n td {\n border: 1px solid #ddd !important;\n }\n }\n\n // Bootstrap specific changes end\n}\n","//\n// Glyphicons for Bootstrap\n//\n// Since icons are fonts, they can be placed anywhere text is placed and are\n// thus automatically sized to match the surrounding child. To use, create an\n// inline element with the appropriate classes, like so:\n//\n// Star\n\n// Import the fonts\n@font-face {\n font-family: 'Glyphicons Halflings';\n src: url('@{icon-font-path}@{icon-font-name}.eot');\n src: url('@{icon-font-path}@{icon-font-name}.eot?#iefix') format('embedded-opentype'),\n url('@{icon-font-path}@{icon-font-name}.woff') format('woff'),\n url('@{icon-font-path}@{icon-font-name}.ttf') format('truetype'),\n url('@{icon-font-path}@{icon-font-name}.svg#@{icon-font-svg-id}') format('svg');\n}\n\n// Catchall baseclass\n.glyphicon {\n position: relative;\n top: 1px;\n display: inline-block;\n font-family: 'Glyphicons Halflings';\n font-style: normal;\n font-weight: normal;\n line-height: 1;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n// Individual icons\n.glyphicon-asterisk { &:before { content: \"\\2a\"; } }\n.glyphicon-plus { &:before { content: \"\\2b\"; } }\n.glyphicon-euro,\n.glyphicon-eur { &:before { content: \"\\20ac\"; } }\n.glyphicon-minus { &:before { content: \"\\2212\"; } }\n.glyphicon-cloud { &:before { content: \"\\2601\"; } }\n.glyphicon-envelope { &:before { content: \"\\2709\"; } }\n.glyphicon-pencil { &:before { content: \"\\270f\"; } }\n.glyphicon-glass { &:before { content: \"\\e001\"; } }\n.glyphicon-music { &:before { content: \"\\e002\"; } }\n.glyphicon-search { &:before { content: \"\\e003\"; } }\n.glyphicon-heart { &:before { content: \"\\e005\"; } }\n.glyphicon-star { &:before { content: \"\\e006\"; } }\n.glyphicon-star-empty { &:before { content: \"\\e007\"; } }\n.glyphicon-user { &:before { content: \"\\e008\"; } }\n.glyphicon-film { &:before { content: \"\\e009\"; } }\n.glyphicon-th-large { &:before { content: \"\\e010\"; } }\n.glyphicon-th { &:before { content: \"\\e011\"; } }\n.glyphicon-th-list { &:before { content: \"\\e012\"; } }\n.glyphicon-ok { &:before { content: \"\\e013\"; } }\n.glyphicon-remove { &:before { content: \"\\e014\"; } }\n.glyphicon-zoom-in { &:before { content: \"\\e015\"; } }\n.glyphicon-zoom-out { &:before { content: \"\\e016\"; } }\n.glyphicon-off { &:before { content: \"\\e017\"; } }\n.glyphicon-signal { &:before { content: \"\\e018\"; } }\n.glyphicon-cog { &:before { content: \"\\e019\"; } }\n.glyphicon-trash { &:before { content: \"\\e020\"; } }\n.glyphicon-home { &:before { content: \"\\e021\"; } }\n.glyphicon-file { &:before { content: \"\\e022\"; } }\n.glyphicon-time { &:before { content: \"\\e023\"; } }\n.glyphicon-road { &:before { content: \"\\e024\"; } }\n.glyphicon-download-alt { &:before { content: \"\\e025\"; } }\n.glyphicon-download { &:before { content: \"\\e026\"; } }\n.glyphicon-upload { &:before { content: \"\\e027\"; } }\n.glyphicon-inbox { &:before { content: \"\\e028\"; } }\n.glyphicon-play-circle { &:before { content: \"\\e029\"; } }\n.glyphicon-repeat { &:before { content: \"\\e030\"; } }\n.glyphicon-refresh { &:before { content: \"\\e031\"; } }\n.glyphicon-list-alt { &:before { content: \"\\e032\"; } }\n.glyphicon-lock { &:before { content: \"\\e033\"; } }\n.glyphicon-flag { &:before { content: \"\\e034\"; } }\n.glyphicon-headphones { &:before { content: \"\\e035\"; } }\n.glyphicon-volume-off { &:before { content: \"\\e036\"; } }\n.glyphicon-volume-down { &:before { content: \"\\e037\"; } }\n.glyphicon-volume-up { &:before { content: \"\\e038\"; } }\n.glyphicon-qrcode { &:before { content: \"\\e039\"; } }\n.glyphicon-barcode { &:before { content: \"\\e040\"; } }\n.glyphicon-tag { &:before { content: \"\\e041\"; } }\n.glyphicon-tags { &:before { content: \"\\e042\"; } }\n.glyphicon-book { &:before { content: \"\\e043\"; } }\n.glyphicon-bookmark { &:before { content: \"\\e044\"; } }\n.glyphicon-print { &:before { content: \"\\e045\"; } }\n.glyphicon-camera { &:before { content: \"\\e046\"; } }\n.glyphicon-font { &:before { content: \"\\e047\"; } }\n.glyphicon-bold { &:before { content: \"\\e048\"; } }\n.glyphicon-italic { &:before { content: \"\\e049\"; } }\n.glyphicon-text-height { &:before { content: \"\\e050\"; } }\n.glyphicon-text-width { &:before { content: \"\\e051\"; } }\n.glyphicon-align-left { &:before { content: \"\\e052\"; } }\n.glyphicon-align-center { &:before { content: \"\\e053\"; } }\n.glyphicon-align-right { &:before { content: \"\\e054\"; } }\n.glyphicon-align-justify { &:before { content: \"\\e055\"; } }\n.glyphicon-list { &:before { content: \"\\e056\"; } }\n.glyphicon-indent-left { &:before { content: \"\\e057\"; } }\n.glyphicon-indent-right { &:before { content: \"\\e058\"; } }\n.glyphicon-facetime-video { &:before { content: \"\\e059\"; } }\n.glyphicon-picture { &:before { content: \"\\e060\"; } }\n.glyphicon-map-marker { &:before { content: \"\\e062\"; } }\n.glyphicon-adjust { &:before { content: \"\\e063\"; } }\n.glyphicon-tint { &:before { content: \"\\e064\"; } }\n.glyphicon-edit { &:before { content: \"\\e065\"; } }\n.glyphicon-share { &:before { content: \"\\e066\"; } }\n.glyphicon-check { &:before { content: \"\\e067\"; } }\n.glyphicon-move { &:before { content: \"\\e068\"; } }\n.glyphicon-step-backward { &:before { content: \"\\e069\"; } }\n.glyphicon-fast-backward { &:before { content: \"\\e070\"; } }\n.glyphicon-backward { &:before { content: \"\\e071\"; } }\n.glyphicon-play { &:before { content: \"\\e072\"; } }\n.glyphicon-pause { &:before { content: \"\\e073\"; } }\n.glyphicon-stop { &:before { content: \"\\e074\"; } }\n.glyphicon-forward { &:before { content: \"\\e075\"; } }\n.glyphicon-fast-forward { &:before { content: \"\\e076\"; } }\n.glyphicon-step-forward { &:before { content: \"\\e077\"; } }\n.glyphicon-eject { &:before { content: \"\\e078\"; } }\n.glyphicon-chevron-left { &:before { content: \"\\e079\"; } }\n.glyphicon-chevron-right { &:before { content: \"\\e080\"; } }\n.glyphicon-plus-sign { &:before { content: \"\\e081\"; } }\n.glyphicon-minus-sign { &:before { content: \"\\e082\"; } }\n.glyphicon-remove-sign { &:before { content: \"\\e083\"; } }\n.glyphicon-ok-sign { &:before { content: \"\\e084\"; } }\n.glyphicon-question-sign { &:before { content: \"\\e085\"; } }\n.glyphicon-info-sign { &:before { content: \"\\e086\"; } }\n.glyphicon-screenshot { &:before { content: \"\\e087\"; } }\n.glyphicon-remove-circle { &:before { content: \"\\e088\"; } }\n.glyphicon-ok-circle { &:before { content: \"\\e089\"; } }\n.glyphicon-ban-circle { &:before { content: \"\\e090\"; } }\n.glyphicon-arrow-left { &:before { content: \"\\e091\"; } }\n.glyphicon-arrow-right { &:before { content: \"\\e092\"; } }\n.glyphicon-arrow-up { &:before { content: \"\\e093\"; } }\n.glyphicon-arrow-down { &:before { content: \"\\e094\"; } }\n.glyphicon-share-alt { &:before { content: \"\\e095\"; } }\n.glyphicon-resize-full { &:before { content: \"\\e096\"; } }\n.glyphicon-resize-small { &:before { content: \"\\e097\"; } }\n.glyphicon-exclamation-sign { &:before { content: \"\\e101\"; } }\n.glyphicon-gift { &:before { content: \"\\e102\"; } }\n.glyphicon-leaf { &:before { content: \"\\e103\"; } }\n.glyphicon-fire { &:before { content: \"\\e104\"; } }\n.glyphicon-eye-open { &:before { content: \"\\e105\"; } }\n.glyphicon-eye-close { &:before { content: \"\\e106\"; } }\n.glyphicon-warning-sign { &:before { content: \"\\e107\"; } }\n.glyphicon-plane { &:before { content: \"\\e108\"; } }\n.glyphicon-calendar { &:before { content: \"\\e109\"; } }\n.glyphicon-random { &:before { content: \"\\e110\"; } }\n.glyphicon-comment { &:before { content: \"\\e111\"; } }\n.glyphicon-magnet { &:before { content: \"\\e112\"; } }\n.glyphicon-chevron-up { &:before { content: \"\\e113\"; } }\n.glyphicon-chevron-down { &:before { content: \"\\e114\"; } }\n.glyphicon-retweet { &:before { content: \"\\e115\"; } }\n.glyphicon-shopping-cart { &:before { content: \"\\e116\"; } }\n.glyphicon-folder-close { &:before { content: \"\\e117\"; } }\n.glyphicon-folder-open { &:before { content: \"\\e118\"; } }\n.glyphicon-resize-vertical { &:before { content: \"\\e119\"; } }\n.glyphicon-resize-horizontal { &:before { content: \"\\e120\"; } }\n.glyphicon-hdd { &:before { content: \"\\e121\"; } }\n.glyphicon-bullhorn { &:before { content: \"\\e122\"; } }\n.glyphicon-bell { &:before { content: \"\\e123\"; } }\n.glyphicon-certificate { &:before { content: \"\\e124\"; } }\n.glyphicon-thumbs-up { &:before { content: \"\\e125\"; } }\n.glyphicon-thumbs-down { &:before { content: \"\\e126\"; } }\n.glyphicon-hand-right { &:before { content: \"\\e127\"; } }\n.glyphicon-hand-left { &:before { content: \"\\e128\"; } }\n.glyphicon-hand-up { &:before { content: \"\\e129\"; } }\n.glyphicon-hand-down { &:before { content: \"\\e130\"; } }\n.glyphicon-circle-arrow-right { &:before { content: \"\\e131\"; } }\n.glyphicon-circle-arrow-left { &:before { content: \"\\e132\"; } }\n.glyphicon-circle-arrow-up { &:before { content: \"\\e133\"; } }\n.glyphicon-circle-arrow-down { &:before { content: \"\\e134\"; } }\n.glyphicon-globe { &:before { content: \"\\e135\"; } }\n.glyphicon-wrench { &:before { content: \"\\e136\"; } }\n.glyphicon-tasks { &:before { content: \"\\e137\"; } }\n.glyphicon-filter { &:before { content: \"\\e138\"; } }\n.glyphicon-briefcase { &:before { content: \"\\e139\"; } }\n.glyphicon-fullscreen { &:before { content: \"\\e140\"; } }\n.glyphicon-dashboard { &:before { content: \"\\e141\"; } }\n.glyphicon-paperclip { &:before { content: \"\\e142\"; } }\n.glyphicon-heart-empty { &:before { content: \"\\e143\"; } }\n.glyphicon-link { &:before { content: \"\\e144\"; } }\n.glyphicon-phone { &:before { content: \"\\e145\"; } }\n.glyphicon-pushpin { &:before { content: \"\\e146\"; } }\n.glyphicon-usd { &:before { content: \"\\e148\"; } }\n.glyphicon-gbp { &:before { content: \"\\e149\"; } }\n.glyphicon-sort { &:before { content: \"\\e150\"; } }\n.glyphicon-sort-by-alphabet { &:before { content: \"\\e151\"; } }\n.glyphicon-sort-by-alphabet-alt { &:before { content: \"\\e152\"; } }\n.glyphicon-sort-by-order { &:before { content: \"\\e153\"; } }\n.glyphicon-sort-by-order-alt { &:before { content: \"\\e154\"; } }\n.glyphicon-sort-by-attributes { &:before { content: \"\\e155\"; } }\n.glyphicon-sort-by-attributes-alt { &:before { content: \"\\e156\"; } }\n.glyphicon-unchecked { &:before { content: \"\\e157\"; } }\n.glyphicon-expand { &:before { content: \"\\e158\"; } }\n.glyphicon-collapse-down { &:before { content: \"\\e159\"; } }\n.glyphicon-collapse-up { &:before { content: \"\\e160\"; } }\n.glyphicon-log-in { &:before { content: \"\\e161\"; } }\n.glyphicon-flash { &:before { content: \"\\e162\"; } }\n.glyphicon-log-out { &:before { content: \"\\e163\"; } }\n.glyphicon-new-window { &:before { content: \"\\e164\"; } }\n.glyphicon-record { &:before { content: \"\\e165\"; } }\n.glyphicon-save { &:before { content: \"\\e166\"; } }\n.glyphicon-open { &:before { content: \"\\e167\"; } }\n.glyphicon-saved { &:before { content: \"\\e168\"; } }\n.glyphicon-import { &:before { content: \"\\e169\"; } }\n.glyphicon-export { &:before { content: \"\\e170\"; } }\n.glyphicon-send { &:before { content: \"\\e171\"; } }\n.glyphicon-floppy-disk { &:before { content: \"\\e172\"; } }\n.glyphicon-floppy-saved { &:before { content: \"\\e173\"; } }\n.glyphicon-floppy-remove { &:before { content: \"\\e174\"; } }\n.glyphicon-floppy-save { &:before { content: \"\\e175\"; } }\n.glyphicon-floppy-open { &:before { content: \"\\e176\"; } }\n.glyphicon-credit-card { &:before { content: \"\\e177\"; } }\n.glyphicon-transfer { &:before { content: \"\\e178\"; } }\n.glyphicon-cutlery { &:before { content: \"\\e179\"; } }\n.glyphicon-header { &:before { content: \"\\e180\"; } }\n.glyphicon-compressed { &:before { content: \"\\e181\"; } }\n.glyphicon-earphone { &:before { content: \"\\e182\"; } }\n.glyphicon-phone-alt { &:before { content: \"\\e183\"; } }\n.glyphicon-tower { &:before { content: \"\\e184\"; } }\n.glyphicon-stats { &:before { content: \"\\e185\"; } }\n.glyphicon-sd-video { &:before { content: \"\\e186\"; } }\n.glyphicon-hd-video { &:before { content: \"\\e187\"; } }\n.glyphicon-subtitles { &:before { content: \"\\e188\"; } }\n.glyphicon-sound-stereo { &:before { content: \"\\e189\"; } }\n.glyphicon-sound-dolby { &:before { content: \"\\e190\"; } }\n.glyphicon-sound-5-1 { &:before { content: \"\\e191\"; } }\n.glyphicon-sound-6-1 { &:before { content: \"\\e192\"; } }\n.glyphicon-sound-7-1 { &:before { content: \"\\e193\"; } }\n.glyphicon-copyright-mark { &:before { content: \"\\e194\"; } }\n.glyphicon-registration-mark { &:before { content: \"\\e195\"; } }\n.glyphicon-cloud-download { &:before { content: \"\\e197\"; } }\n.glyphicon-cloud-upload { &:before { content: \"\\e198\"; } }\n.glyphicon-tree-conifer { &:before { content: \"\\e199\"; } }\n.glyphicon-tree-deciduous { &:before { content: \"\\e200\"; } }\n","//\n// Scaffolding\n// --------------------------------------------------\n\n\n// Reset the box-sizing\n//\n// Heads up! This reset may cause conflicts with some third-party widgets.\n// For recommendations on resolving such conflicts, see\n// http://getbootstrap.com/getting-started/#third-box-sizing\n* {\n .box-sizing(border-box);\n}\n*:before,\n*:after {\n .box-sizing(border-box);\n}\n\n\n// Body reset\n\nhtml {\n font-size: 10px;\n -webkit-tap-highlight-color: rgba(0,0,0,0);\n}\n\nbody {\n font-family: @font-family-base;\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @text-color;\n background-color: @body-bg;\n}\n\n// Reset fonts for relevant elements\ninput,\nbutton,\nselect,\ntextarea {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\n\n\n// Links\n\na {\n color: @link-color;\n text-decoration: none;\n\n &:hover,\n &:focus {\n color: @link-hover-color;\n text-decoration: @link-hover-decoration;\n }\n\n &:focus {\n .tab-focus();\n }\n}\n\n\n// Figures\n//\n// We reset this here because previously Normalize had no `figure` margins. This\n// ensures we don't break anyone's use of the element.\n\nfigure {\n margin: 0;\n}\n\n\n// Images\n\nimg {\n vertical-align: middle;\n}\n\n// Responsive images (ensure images don't scale beyond their parents)\n.img-responsive {\n .img-responsive();\n}\n\n// Rounded corners\n.img-rounded {\n border-radius: @border-radius-large;\n}\n\n// Image thumbnails\n//\n// Heads up! This is mixin-ed into thumbnails.less for `.thumbnail`.\n.img-thumbnail {\n padding: @thumbnail-padding;\n line-height: @line-height-base;\n background-color: @thumbnail-bg;\n border: 1px solid @thumbnail-border;\n border-radius: @thumbnail-border-radius;\n .transition(all .2s ease-in-out);\n\n // Keep them at most 100% wide\n .img-responsive(inline-block);\n}\n\n// Perfect circle\n.img-circle {\n border-radius: 50%; // set radius in percents\n}\n\n\n// Horizontal rules\n\nhr {\n margin-top: @line-height-computed;\n margin-bottom: @line-height-computed;\n border: 0;\n border-top: 1px solid @hr-border;\n}\n\n\n// Only display content to screen readers\n//\n// See: http://a11yproject.com/posts/how-to-hide-content/\n\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0,0,0,0);\n border: 0;\n}\n\n// Use in conjunction with .sr-only to only display content when it's focused.\n// Useful for \"Skip to main content\" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1\n// Credit: HTML5 Boilerplate\n\n.sr-only-focusable {\n &:active,\n &:focus {\n position: static;\n width: auto;\n height: auto;\n margin: 0;\n overflow: visible;\n clip: auto;\n }\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They will be removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility){\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n // Firefox\n &::-moz-placeholder {\n color: @color;\n opacity: 1; // See https://github.com/twbs/bootstrap/pull/11526\n }\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n","// WebKit-style focus\n\n.tab-focus() {\n // Default\n outline: thin dotted;\n // WebKit\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n","// Image Mixins\n// - Responsive image\n// - Retina image\n\n\n// Responsive image\n//\n// Keep images from scaling beyond the width of their parents.\n.img-responsive(@display: block) {\n display: @display;\n max-width: 100%; // Part 1: Set a maximum relative to the parent\n height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching\n}\n\n\n// Retina image\n//\n// Short retina mixin for setting background-image and -size. Note that the\n// spelling of `min--moz-device-pixel-ratio` is intentional.\n.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) {\n background-image: url(\"@{file-1x}\");\n\n @media\n only screen and (-webkit-min-device-pixel-ratio: 2),\n only screen and ( min--moz-device-pixel-ratio: 2),\n only screen and ( -o-min-device-pixel-ratio: 2/1),\n only screen and ( min-device-pixel-ratio: 2),\n only screen and ( min-resolution: 192dpi),\n only screen and ( min-resolution: 2dppx) {\n background-image: url(\"@{file-2x}\");\n background-size: @width-1x @height-1x;\n }\n}\n","//\n// Typography\n// --------------------------------------------------\n\n\n// Headings\n// -------------------------\n\nh1, h2, h3, h4, h5, h6,\n.h1, .h2, .h3, .h4, .h5, .h6 {\n font-family: @headings-font-family;\n font-weight: @headings-font-weight;\n line-height: @headings-line-height;\n color: @headings-color;\n\n small,\n .small {\n font-weight: normal;\n line-height: 1;\n color: @headings-small-color;\n }\n}\n\nh1, .h1,\nh2, .h2,\nh3, .h3 {\n margin-top: @line-height-computed;\n margin-bottom: (@line-height-computed / 2);\n\n small,\n .small {\n font-size: 65%;\n }\n}\nh4, .h4,\nh5, .h5,\nh6, .h6 {\n margin-top: (@line-height-computed / 2);\n margin-bottom: (@line-height-computed / 2);\n\n small,\n .small {\n font-size: 75%;\n }\n}\n\nh1, .h1 { font-size: @font-size-h1; }\nh2, .h2 { font-size: @font-size-h2; }\nh3, .h3 { font-size: @font-size-h3; }\nh4, .h4 { font-size: @font-size-h4; }\nh5, .h5 { font-size: @font-size-h5; }\nh6, .h6 { font-size: @font-size-h6; }\n\n\n// Body text\n// -------------------------\n\np {\n margin: 0 0 (@line-height-computed / 2);\n}\n\n.lead {\n margin-bottom: @line-height-computed;\n font-size: floor((@font-size-base * 1.15));\n font-weight: 300;\n line-height: 1.4;\n\n @media (min-width: @screen-sm-min) {\n font-size: (@font-size-base * 1.5);\n }\n}\n\n\n// Emphasis & misc\n// -------------------------\n\n// Ex: (12px small font / 14px base font) * 100% = about 85%\nsmall,\n.small {\n font-size: floor((100% * @font-size-small / @font-size-base));\n}\n\nmark,\n.mark {\n background-color: @state-warning-bg;\n padding: .2em;\n}\n\n// Alignment\n.text-left { text-align: left; }\n.text-right { text-align: right; }\n.text-center { text-align: center; }\n.text-justify { text-align: justify; }\n.text-nowrap { white-space: nowrap; }\n\n// Transformation\n.text-lowercase { text-transform: lowercase; }\n.text-uppercase { text-transform: uppercase; }\n.text-capitalize { text-transform: capitalize; }\n\n// Contextual colors\n.text-muted {\n color: @text-muted;\n}\n.text-primary {\n .text-emphasis-variant(@brand-primary);\n}\n.text-success {\n .text-emphasis-variant(@state-success-text);\n}\n.text-info {\n .text-emphasis-variant(@state-info-text);\n}\n.text-warning {\n .text-emphasis-variant(@state-warning-text);\n}\n.text-danger {\n .text-emphasis-variant(@state-danger-text);\n}\n\n// Contextual backgrounds\n// For now we'll leave these alongside the text classes until v4 when we can\n// safely shift things around (per SemVer rules).\n.bg-primary {\n // Given the contrast here, this is the only class to have its color inverted\n // automatically.\n color: #fff;\n .bg-variant(@brand-primary);\n}\n.bg-success {\n .bg-variant(@state-success-bg);\n}\n.bg-info {\n .bg-variant(@state-info-bg);\n}\n.bg-warning {\n .bg-variant(@state-warning-bg);\n}\n.bg-danger {\n .bg-variant(@state-danger-bg);\n}\n\n\n// Page header\n// -------------------------\n\n.page-header {\n padding-bottom: ((@line-height-computed / 2) - 1);\n margin: (@line-height-computed * 2) 0 @line-height-computed;\n border-bottom: 1px solid @page-header-border-color;\n}\n\n\n// Lists\n// -------------------------\n\n// Unordered and Ordered lists\nul,\nol {\n margin-top: 0;\n margin-bottom: (@line-height-computed / 2);\n ul,\n ol {\n margin-bottom: 0;\n }\n}\n\n// List options\n\n// Unstyled keeps list items block level, just removes default browser padding and list-style\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n\n// Inline turns list items into inline-block\n.list-inline {\n .list-unstyled();\n margin-left: -5px;\n\n > li {\n display: inline-block;\n padding-left: 5px;\n padding-right: 5px;\n }\n}\n\n// Description Lists\ndl {\n margin-top: 0; // Remove browser default\n margin-bottom: @line-height-computed;\n}\ndt,\ndd {\n line-height: @line-height-base;\n}\ndt {\n font-weight: bold;\n}\ndd {\n margin-left: 0; // Undo browser default\n}\n\n// Horizontal description lists\n//\n// Defaults to being stacked without any of the below styles applied, until the\n// grid breakpoint is reached (default of ~768px).\n\n.dl-horizontal {\n dd {\n &:extend(.clearfix all); // Clear the floated `dt` if an empty `dd` is present\n }\n\n @media (min-width: @grid-float-breakpoint) {\n dt {\n float: left;\n width: (@dl-horizontal-offset - 20);\n clear: left;\n text-align: right;\n .text-overflow();\n }\n dd {\n margin-left: @dl-horizontal-offset;\n }\n }\n}\n\n\n// Misc\n// -------------------------\n\n// Abbreviations and acronyms\nabbr[title],\n// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257\nabbr[data-original-title] {\n cursor: help;\n border-bottom: 1px dotted @abbr-border-color;\n}\n.initialism {\n font-size: 90%;\n text-transform: uppercase;\n}\n\n// Blockquotes\nblockquote {\n padding: (@line-height-computed / 2) @line-height-computed;\n margin: 0 0 @line-height-computed;\n font-size: @blockquote-font-size;\n border-left: 5px solid @blockquote-border-color;\n\n p,\n ul,\n ol {\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n // Note: Deprecated small and .small as of v3.1.0\n // Context: https://github.com/twbs/bootstrap/issues/11660\n footer,\n small,\n .small {\n display: block;\n font-size: 80%; // back to default font-size\n line-height: @line-height-base;\n color: @blockquote-small-color;\n\n &:before {\n content: '\\2014 \\00A0'; // em dash, nbsp\n }\n }\n}\n\n// Opposite alignment of blockquote\n//\n// Heads up: `blockquote.pull-right` has been deprecated as of v3.1.0.\n.blockquote-reverse,\nblockquote.pull-right {\n padding-right: 15px;\n padding-left: 0;\n border-right: 5px solid @blockquote-border-color;\n border-left: 0;\n text-align: right;\n\n // Account for citation\n footer,\n small,\n .small {\n &:before { content: ''; }\n &:after {\n content: '\\00A0 \\2014'; // nbsp, em dash\n }\n }\n}\n\n// Addresses\naddress {\n margin-bottom: @line-height-computed;\n font-style: normal;\n line-height: @line-height-base;\n}\n","// Typography\n\n.text-emphasis-variant(@color) {\n color: @color;\n a&:hover {\n color: darken(@color, 10%);\n }\n}\n","// Contextual backgrounds\n\n.bg-variant(@color) {\n background-color: @color;\n a&:hover {\n background-color: darken(@color, 10%);\n }\n}\n","// Text overflow\n// Requires inline-block or block for proper styling\n\n.text-overflow() {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n","//\n// Code (inline and block)\n// --------------------------------------------------\n\n\n// Inline and block code styles\ncode,\nkbd,\npre,\nsamp {\n font-family: @font-family-monospace;\n}\n\n// Inline code\ncode {\n padding: 2px 4px;\n font-size: 90%;\n color: @code-color;\n background-color: @code-bg;\n border-radius: @border-radius-base;\n}\n\n// User input typically entered via keyboard\nkbd {\n padding: 2px 4px;\n font-size: 90%;\n color: @kbd-color;\n background-color: @kbd-bg;\n border-radius: @border-radius-small;\n box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);\n\n kbd {\n padding: 0;\n font-size: 100%;\n font-weight: bold;\n box-shadow: none;\n }\n}\n\n// Blocks of code\npre {\n display: block;\n padding: ((@line-height-computed - 1) / 2);\n margin: 0 0 (@line-height-computed / 2);\n font-size: (@font-size-base - 1); // 14px to 13px\n line-height: @line-height-base;\n word-break: break-all;\n word-wrap: break-word;\n color: @pre-color;\n background-color: @pre-bg;\n border: 1px solid @pre-border-color;\n border-radius: @border-radius-base;\n\n // Account for some code outputs that place code tags in pre tags\n code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre-wrap;\n background-color: transparent;\n border-radius: 0;\n }\n}\n\n// Enable scrollable blocks of code\n.pre-scrollable {\n max-height: @pre-scrollable-max-height;\n overflow-y: scroll;\n}\n","//\n// Grid system\n// --------------------------------------------------\n\n\n// Container widths\n//\n// Set the container width, and override it for fixed navbars in media queries.\n\n.container {\n .container-fixed();\n\n @media (min-width: @screen-sm-min) {\n width: @container-sm;\n }\n @media (min-width: @screen-md-min) {\n width: @container-md;\n }\n @media (min-width: @screen-lg-min) {\n width: @container-lg;\n }\n}\n\n\n// Fluid container\n//\n// Utilizes the mixin meant for fixed width containers, but without any defined\n// width for fluid, full width layouts.\n\n.container-fluid {\n .container-fixed();\n}\n\n\n// Row\n//\n// Rows contain and clear the floats of your columns.\n\n.row {\n .make-row();\n}\n\n\n// Columns\n//\n// Common styles for small and large grid columns\n\n.make-grid-columns();\n\n\n// Extra small grid\n//\n// Columns, offsets, pushes, and pulls for extra small devices like\n// smartphones.\n\n.make-grid(xs);\n\n\n// Small grid\n//\n// Columns, offsets, pushes, and pulls for the small device range, from phones\n// to tablets.\n\n@media (min-width: @screen-sm-min) {\n .make-grid(sm);\n}\n\n\n// Medium grid\n//\n// Columns, offsets, pushes, and pulls for the desktop device range.\n\n@media (min-width: @screen-md-min) {\n .make-grid(md);\n}\n\n\n// Large grid\n//\n// Columns, offsets, pushes, and pulls for the large desktop device range.\n\n@media (min-width: @screen-lg-min) {\n .make-grid(lg);\n}\n","// Grid system\n//\n// Generate semantic grid columns with these mixins.\n\n// Centered container element\n.container-fixed(@gutter: @grid-gutter-width) {\n margin-right: auto;\n margin-left: auto;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n &:extend(.clearfix all);\n}\n\n// Creates a wrapper for a series of columns\n.make-row(@gutter: @grid-gutter-width) {\n margin-left: (@gutter / -2);\n margin-right: (@gutter / -2);\n &:extend(.clearfix all);\n}\n\n// Generate the extra small columns\n.make-xs-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n float: left;\n width: percentage((@columns / @grid-columns));\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n}\n.make-xs-column-offset(@columns) {\n margin-left: percentage((@columns / @grid-columns));\n}\n.make-xs-column-push(@columns) {\n left: percentage((@columns / @grid-columns));\n}\n.make-xs-column-pull(@columns) {\n right: percentage((@columns / @grid-columns));\n}\n\n// Generate the small columns\n.make-sm-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-sm-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-offset(@columns) {\n @media (min-width: @screen-sm-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-push(@columns) {\n @media (min-width: @screen-sm-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-pull(@columns) {\n @media (min-width: @screen-sm-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n// Generate the medium columns\n.make-md-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-md-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-offset(@columns) {\n @media (min-width: @screen-md-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-push(@columns) {\n @media (min-width: @screen-md-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-pull(@columns) {\n @media (min-width: @screen-md-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n// Generate the large columns\n.make-lg-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-lg-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-offset(@columns) {\n @media (min-width: @screen-lg-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-push(@columns) {\n @media (min-width: @screen-lg-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-pull(@columns) {\n @media (min-width: @screen-lg-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n","// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `@grid-columns`.\n\n.make-grid-columns() {\n // Common styles for all sizes of grid columns, widths 1-12\n .col(@index) when (@index = 1) { // initial\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general; \"=<\" isn't a typo\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n position: relative;\n // Prevent columns from collapsing when empty\n min-height: 1px;\n // Inner gutter via padding\n padding-left: (@grid-gutter-width / 2);\n padding-right: (@grid-gutter-width / 2);\n }\n }\n .col(1); // kickstart it\n}\n\n.float-grid-columns(@class) {\n .col(@index) when (@index = 1) { // initial\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n float: left;\n }\n }\n .col(1); // kickstart it\n}\n\n.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) {\n .col-@{class}-@{index} {\n width: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) and (@index > 0) {\n .col-@{class}-push-@{index} {\n left: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) and (@index = 0) {\n .col-@{class}-push-0 {\n left: auto;\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index > 0) {\n .col-@{class}-pull-@{index} {\n right: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index = 0) {\n .col-@{class}-pull-0 {\n right: auto;\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = offset) {\n .col-@{class}-offset-@{index} {\n margin-left: percentage((@index / @grid-columns));\n }\n}\n\n// Basic looping in LESS\n.loop-grid-columns(@index, @class, @type) when (@index >= 0) {\n .calc-grid-column(@index, @class, @type);\n // next iteration\n .loop-grid-columns((@index - 1), @class, @type);\n}\n\n// Create grid for specific class\n.make-grid(@class) {\n .float-grid-columns(@class);\n .loop-grid-columns(@grid-columns, @class, width);\n .loop-grid-columns(@grid-columns, @class, pull);\n .loop-grid-columns(@grid-columns, @class, push);\n .loop-grid-columns(@grid-columns, @class, offset);\n}\n","//\n// Tables\n// --------------------------------------------------\n\n\ntable {\n background-color: @table-bg;\n}\ncaption {\n padding-top: @table-cell-padding;\n padding-bottom: @table-cell-padding;\n color: @text-muted;\n text-align: left;\n}\nth {\n text-align: left;\n}\n\n\n// Baseline styles\n\n.table {\n width: 100%;\n max-width: 100%;\n margin-bottom: @line-height-computed;\n // Cells\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n padding: @table-cell-padding;\n line-height: @line-height-base;\n vertical-align: top;\n border-top: 1px solid @table-border-color;\n }\n }\n }\n // Bottom align for column headings\n > thead > tr > th {\n vertical-align: bottom;\n border-bottom: 2px solid @table-border-color;\n }\n // Remove top border from thead by default\n > caption + thead,\n > colgroup + thead,\n > thead:first-child {\n > tr:first-child {\n > th,\n > td {\n border-top: 0;\n }\n }\n }\n // Account for multiple tbody instances\n > tbody + tbody {\n border-top: 2px solid @table-border-color;\n }\n\n // Nesting\n .table {\n background-color: @body-bg;\n }\n}\n\n\n// Condensed table w/ half padding\n\n.table-condensed {\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n padding: @table-condensed-cell-padding;\n }\n }\n }\n}\n\n\n// Bordered version\n//\n// Add borders all around the table and between all the columns.\n\n.table-bordered {\n border: 1px solid @table-border-color;\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n border: 1px solid @table-border-color;\n }\n }\n }\n > thead > tr {\n > th,\n > td {\n border-bottom-width: 2px;\n }\n }\n}\n\n\n// Zebra-striping\n//\n// Default zebra-stripe styles (alternating gray and transparent backgrounds)\n\n.table-striped {\n > tbody > tr:nth-child(odd) {\n background-color: @table-bg-accent;\n }\n}\n\n\n// Hover effect\n//\n// Placed here since it has to come after the potential zebra striping\n\n.table-hover {\n > tbody > tr:hover {\n background-color: @table-bg-hover;\n }\n}\n\n\n// Table cell sizing\n//\n// Reset default table behavior\n\ntable col[class*=\"col-\"] {\n position: static; // Prevent border hiding in Firefox and IE9/10 (see https://github.com/twbs/bootstrap/issues/11623)\n float: none;\n display: table-column;\n}\ntable {\n td,\n th {\n &[class*=\"col-\"] {\n position: static; // Prevent border hiding in Firefox and IE9/10 (see https://github.com/twbs/bootstrap/issues/11623)\n float: none;\n display: table-cell;\n }\n }\n}\n\n\n// Table backgrounds\n//\n// Exact selectors below required to override `.table-striped` and prevent\n// inheritance to nested tables.\n\n// Generate the contextual variants\n.table-row-variant(active; @table-bg-active);\n.table-row-variant(success; @state-success-bg);\n.table-row-variant(info; @state-info-bg);\n.table-row-variant(warning; @state-warning-bg);\n.table-row-variant(danger; @state-danger-bg);\n\n\n// Responsive tables\n//\n// Wrap your tables in `.table-responsive` and we'll make them mobile friendly\n// by enabling horizontal scrolling. Only applies <768px. Everything above that\n// will display normally.\n\n.table-responsive {\n overflow-x: auto;\n min-height: 0.01%; // Workaround for IE9 bug (see https://github.com/twbs/bootstrap/issues/14837)\n\n @media screen and (max-width: @screen-xs-max) {\n width: 100%;\n margin-bottom: (@line-height-computed * 0.75);\n overflow-y: hidden;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n border: 1px solid @table-border-color;\n\n // Tighten up spacing\n > .table {\n margin-bottom: 0;\n\n // Ensure the content doesn't wrap\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n white-space: nowrap;\n }\n }\n }\n }\n\n // Special overrides for the bordered tables\n > .table-bordered {\n border: 0;\n\n // Nuke the appropriate borders so that the parent can handle them\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th:first-child,\n > td:first-child {\n border-left: 0;\n }\n > th:last-child,\n > td:last-child {\n border-right: 0;\n }\n }\n }\n\n // Only nuke the last row's bottom-border in `tbody` and `tfoot` since\n // chances are there will be only one `tr` in a `thead` and that would\n // remove the border altogether.\n > tbody,\n > tfoot {\n > tr:last-child {\n > th,\n > td {\n border-bottom: 0;\n }\n }\n }\n\n }\n }\n}\n","// Tables\n\n.table-row-variant(@state; @background) {\n // Exact selectors below required to override `.table-striped` and prevent\n // inheritance to nested tables.\n .table > thead > tr,\n .table > tbody > tr,\n .table > tfoot > tr {\n > td.@{state},\n > th.@{state},\n &.@{state} > td,\n &.@{state} > th {\n background-color: @background;\n }\n }\n\n // Hover states for `.table-hover`\n // Note: this is not available for cells or rows within `thead` or `tfoot`.\n .table-hover > tbody > tr {\n > td.@{state}:hover,\n > th.@{state}:hover,\n &.@{state}:hover > td,\n &:hover > .@{state},\n &.@{state}:hover > th {\n background-color: darken(@background, 5%);\n }\n }\n}\n","//\n// Forms\n// --------------------------------------------------\n\n\n// Normalize non-controls\n//\n// Restyle and baseline non-control form elements.\n\nfieldset {\n padding: 0;\n margin: 0;\n border: 0;\n // Chrome and Firefox set a `min-width: min-content;` on fieldsets,\n // so we reset that to ensure it behaves more like a standard block element.\n // See https://github.com/twbs/bootstrap/issues/12359.\n min-width: 0;\n}\n\nlegend {\n display: block;\n width: 100%;\n padding: 0;\n margin-bottom: @line-height-computed;\n font-size: (@font-size-base * 1.5);\n line-height: inherit;\n color: @legend-color;\n border: 0;\n border-bottom: 1px solid @legend-border-color;\n}\n\nlabel {\n display: inline-block;\n max-width: 100%; // Force IE8 to wrap long content (see https://github.com/twbs/bootstrap/issues/13141)\n margin-bottom: 5px;\n font-weight: bold;\n}\n\n\n// Normalize form controls\n//\n// While most of our form styles require extra classes, some basic normalization\n// is required to ensure optimum display with or without those classes to better\n// address browser inconsistencies.\n\n// Override content-box in Normalize (* isn't specific enough)\ninput[type=\"search\"] {\n .box-sizing(border-box);\n}\n\n// Position radios and checkboxes better\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n margin: 4px 0 0;\n margin-top: 1px \\9; // IE8-9\n line-height: normal;\n}\n\n// Set the height of file controls to match text inputs\ninput[type=\"file\"] {\n display: block;\n}\n\n// Make range inputs behave like textual form controls\ninput[type=\"range\"] {\n display: block;\n width: 100%;\n}\n\n// Make multiple select elements height not fixed\nselect[multiple],\nselect[size] {\n height: auto;\n}\n\n// Focus for file, radio, and checkbox\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n .tab-focus();\n}\n\n// Adjust output element\noutput {\n display: block;\n padding-top: (@padding-base-vertical + 1);\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @input-color;\n}\n\n\n// Common form controls\n//\n// Shared size and type resets for form controls. Apply `.form-control` to any\n// of the following form controls:\n//\n// select\n// textarea\n// input[type=\"text\"]\n// input[type=\"password\"]\n// input[type=\"datetime\"]\n// input[type=\"datetime-local\"]\n// input[type=\"date\"]\n// input[type=\"month\"]\n// input[type=\"time\"]\n// input[type=\"week\"]\n// input[type=\"number\"]\n// input[type=\"email\"]\n// input[type=\"url\"]\n// input[type=\"search\"]\n// input[type=\"tel\"]\n// input[type=\"color\"]\n\n.form-control {\n display: block;\n width: 100%;\n height: @input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border)\n padding: @padding-base-vertical @padding-base-horizontal;\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @input-color;\n background-color: @input-bg;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid @input-border;\n border-radius: @input-border-radius;\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.075));\n .transition(~\"border-color ease-in-out .15s, box-shadow ease-in-out .15s\");\n\n // Customize the `:focus` state to imitate native WebKit styles.\n .form-control-focus();\n\n // Placeholder\n .placeholder();\n\n // Disabled and read-only inputs\n //\n // HTML5 says that controls under a fieldset > legend:first-child won't be\n // disabled if the fieldset is disabled. Due to implementation difficulty, we\n // don't honor that edge case; we style them as disabled anyway.\n &[disabled],\n &[readonly],\n fieldset[disabled] & {\n cursor: @cursor-disabled;\n background-color: @input-bg-disabled;\n opacity: 1; // iOS fix for unreadable disabled content\n }\n\n // Reset height for `textarea`s\n textarea& {\n height: auto;\n }\n}\n\n\n// Search inputs in iOS\n//\n// This overrides the extra rounded corners on search inputs in iOS so that our\n// `.form-control` class can properly style them. Note that this cannot simply\n// be added to `.form-control` as it's not specific enough. For details, see\n// https://github.com/twbs/bootstrap/issues/11586.\n\ninput[type=\"search\"] {\n -webkit-appearance: none;\n}\n\n\n// Special styles for iOS temporal inputs\n//\n// In Mobile Safari, setting `display: block` on temporal inputs causes the\n// text within the input to become vertically misaligned.\n// As a workaround, we set a pixel line-height that matches the\n// given height of the input. Since this fucks up everything else, we have to\n// appropriately reset it for Internet Explorer and the size variations.\n\ninput[type=\"date\"],\ninput[type=\"time\"],\ninput[type=\"datetime-local\"],\ninput[type=\"month\"] {\n line-height: @input-height-base;\n // IE8+ misaligns the text within date inputs, so we reset\n line-height: @line-height-base ~\"\\0\";\n\n &.input-sm {\n line-height: @input-height-small;\n line-height: @line-height-small ~\"\\0\";\n }\n &.input-lg {\n line-height: @input-height-large;\n line-height: @line-height-large ~\"\\0\";\n }\n}\n\n// IE 11 hack to reverse the iOS temporal input hack.\n_:-ms-fullscreen, :root input[type=\"date\"],\n_:-ms-fullscreen, :root input[type=\"time\"],\n_:-ms-fullscreen, :root input[type=\"datetime-local\"],\n_:-ms-fullscreen, :root input[type=\"month\"] {\n line-height: @line-height-base;\n\n &.input-sm {\n line-height: @line-height-small;\n }\n &.input-lg {\n line-height: @line-height-large;\n }\n}\n\n\n// Form groups\n//\n// Designed to help with the organization and spacing of vertical forms. For\n// horizontal forms, use the predefined grid classes.\n\n.form-group {\n margin-bottom: 15px;\n}\n\n\n// Checkboxes and radios\n//\n// Indent the labels to position radios/checkboxes as hanging controls.\n\n.radio,\n.checkbox {\n position: relative;\n display: block;\n margin-top: 10px;\n margin-bottom: 10px;\n\n label {\n min-height: @line-height-computed; // Ensure the input doesn't jump when there is no text\n padding-left: 20px;\n margin-bottom: 0;\n font-weight: normal;\n cursor: pointer;\n }\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n position: absolute;\n margin-left: -20px;\n margin-top: 4px \\9;\n}\n\n.radio + .radio,\n.checkbox + .checkbox {\n margin-top: -5px; // Move up sibling radios or checkboxes for tighter spacing\n}\n\n// Radios and checkboxes on same line\n.radio-inline,\n.checkbox-inline {\n display: inline-block;\n padding-left: 20px;\n margin-bottom: 0;\n vertical-align: middle;\n font-weight: normal;\n cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n margin-top: 0;\n margin-left: 10px; // space out consecutive inline controls\n}\n\n// Apply same disabled cursor tweak as for inputs\n// Some special care is needed because
    + ``` + + `unbound` can also be used in conjunction with a bound helper to + render it in its unbound form: + + ```handlebars +
    {{unbound helperName somePropertyThatDoesntChange}}
    + ``` + + @method unbound + @for Ember.Handlebars.helpers + @param {String} property + @return {String} HTML string + */ + __exports__["default"] = function unboundHelper(property, fn) { + var options = arguments[arguments.length - 1]; + var container = options.data.view.container; + var helper, context, out, ctx; + + ctx = this; + if (arguments.length > 2) { + // Unbound helper call. + options.data.isUnbound = true; + helper = resolveHelper(container, property) || helpers.helperMissing; + out = helper.apply(ctx, slice.call(arguments, 1)); + delete options.data.isUnbound; + return out; + } + + context = (fn.contexts && fn.contexts.length) ? fn.contexts[0] : ctx; + return handlebarsGet(context, property, fn); + } + }); +enifed("ember-handlebars/helpers/view", + ["ember-metal/core","ember-runtime/system/object","ember-metal/property_get","ember-metal/property_set","ember-metal/mixin","ember-views/system/jquery","ember-views/views/view","ember-metal/binding","ember-metal/keys","ember-handlebars/ext","ember-runtime/system/string","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { + "use strict"; + /*globals Handlebars */ + + /** + @module ember + @submodule ember-handlebars + */ + + var Ember = __dependency1__["default"]; + // Ember.warn, Ember.assert + // var emberWarn = Ember.warn, emberAssert = Ember.assert; + + var EmberObject = __dependency2__["default"]; + var get = __dependency3__.get; + var set = __dependency4__.set; + var IS_BINDING = __dependency5__.IS_BINDING; + var jQuery = __dependency6__["default"]; + var View = __dependency7__["default"]; + var isGlobalPath = __dependency8__.isGlobalPath; + var keys = __dependency9__["default"]; + var normalizePath = __dependency10__.normalizePath; + var handlebarsGet = __dependency10__.handlebarsGet; + var handlebarsGetView = __dependency10__.handlebarsGetView; + var EmberString = __dependency11__["default"]; + + + var LOWERCASE_A_Z = /^[a-z]/; + var VIEW_PREFIX = /^view\./; + + function makeBindings(thisContext, options) { + var hash = options.hash; + var hashType = options.hashTypes; + + for (var prop in hash) { + if (hashType[prop] === 'ID') { + + var value = hash[prop]; + + if (IS_BINDING.test(prop)) { + Ember.warn("You're attempting to render a view by passing " + prop + "=" + value + " to a view helper, but this syntax is ambiguous. You should either surround " + value + " in quotes or remove `Binding` from " + prop + "."); + } else { + hash[prop + 'Binding'] = value; + hashType[prop + 'Binding'] = 'STRING'; + delete hash[prop]; + delete hashType[prop]; + } + } + } + + if (hash.hasOwnProperty('idBinding')) { + // id can't be bound, so just perform one-time lookup. + hash.id = handlebarsGet(thisContext, hash.idBinding, options); + hashType.id = 'STRING'; + delete hash.idBinding; + delete hashType.idBinding; + } + } + + var ViewHelper = EmberObject.create({ + propertiesFromHTMLOptions: function(options) { + var hash = options.hash; + var data = options.data; + var classes = hash['class']; + + var extensions = { + helperName: options.helperName || '' + }; + + if (hash.id) { + extensions.elementId = hash.id; + } + + if (hash.tag) { + extensions.tagName = hash.tag; + } + + if (classes) { + classes = classes.split(' '); + extensions.classNames = classes; + } + + if (hash.classBinding) { + extensions.classNameBindings = hash.classBinding.split(' '); + } + + if (hash.classNameBindings) { + if (extensions.classNameBindings === undefined) { + extensions.classNameBindings = []; + } + extensions.classNameBindings = extensions.classNameBindings.concat(hash.classNameBindings.split(' ')); + } + + if (hash.attributeBindings) { + Ember.assert("Setting 'attributeBindings' via Handlebars is not allowed. Please subclass Ember.View and set it there instead."); + extensions.attributeBindings = null; + } + + // Set the proper context for all bindings passed to the helper. This applies to regular attribute bindings + // as well as class name bindings. If the bindings are local, make them relative to the current context + // instead of the view. + var path; + var hashKeys = keys(hash); + + for (var i = 0, l = hashKeys.length; i < l; i++) { + var prop = hashKeys[i]; + var isBinding = IS_BINDING.test(prop); + + if (prop !== 'classNameBindings') { + extensions[prop] = hash[prop]; + } + + // Test if the property ends in "Binding" + if (isBinding && typeof extensions[prop] === 'string') { + path = this.contextualizeBindingPath(hash[prop], data); + if (path) { + extensions[prop] = path; + } + } + } + + if (extensions.classNameBindings) { + // Evaluate the context of class name bindings: + for (var j = 0, k = extensions.classNameBindings.length; j < k; j++) { + var full = extensions.classNameBindings[j]; + + if (typeof full === 'string') { + // Contextualize the path of classNameBinding so this: + // + // classNameBinding="isGreen:green" + // + // is converted to this: + // + // classNameBinding="_parentView.context.isGreen:green" + var parsedPath = View._parsePropertyPath(full); + if (parsedPath.path !== '') { + path = this.contextualizeBindingPath(parsedPath.path, data); + if (path) { + extensions.classNameBindings[j] = path + parsedPath.classNames; + } + } + } + } + } + + return extensions; + }, + + // Transform bindings from the current context to a context that can be evaluated within the view. + // Returns null if the path shouldn't be changed. + // + // TODO: consider the addition of a prefix that would allow this method to return `path`. + contextualizeBindingPath: function(path, data) { + var normalized = normalizePath(null, path, data); + if (normalized.isKeyword) { + return 'templateData.keywords.' + path; + } else if (isGlobalPath(path)) { + return null; + } else if (path === 'this' || path === '') { + return '_parentView.context'; + } else { + return '_parentView.context.' + path; + } + }, + + helper: function(thisContext, path, options) { + var data = options.data; + var fn = options.fn; + var newView; + + makeBindings(thisContext, options); + + var container = this.container || (data && data.view && data.view.container); + newView = handlebarsGetView(thisContext, path, container, options); + + var viewOptions = this.propertiesFromHTMLOptions(options, thisContext); + var currentView = data.view; + viewOptions.templateData = data; + var newViewProto = newView.proto(); + + if (fn) { + Ember.assert("You cannot provide a template block if you also specified a templateName", !get(viewOptions, 'templateName') && !get(newViewProto, 'templateName')); + viewOptions.template = fn; + } + + // We only want to override the `_context` computed property if there is + // no specified controller. See View#_context for more information. + if (!newViewProto.controller && !newViewProto.controllerBinding && !viewOptions.controller && !viewOptions.controllerBinding) { + viewOptions._context = thisContext; + } + + currentView.appendChild(newView, viewOptions); + }, + + instanceHelper: function(thisContext, newView, options) { + var data = options.data; + var fn = options.fn; + + makeBindings(thisContext, options); + + Ember.assert( + 'Only a instance of a view may be passed to the ViewHelper.instanceHelper', + View.detectInstance(newView) + ); + + var viewOptions = this.propertiesFromHTMLOptions(options, thisContext); + var currentView = data.view; + viewOptions.templateData = data; + + if (fn) { + Ember.assert("You cannot provide a template block if you also specified a templateName", !get(viewOptions, 'templateName') && !get(newView, 'templateName')); + viewOptions.template = fn; + } + + // We only want to override the `_context` computed property if there is + // no specified controller. See View#_context for more information. + if (!newView.controller && !newView.controllerBinding && !viewOptions.controller && !viewOptions.controllerBinding) { + viewOptions._context = thisContext; + } + + currentView.appendChild(newView, viewOptions); + } + }); + __exports__.ViewHelper = ViewHelper; + /** + `{{view}}` inserts a new instance of an `Ember.View` into a template passing its + options to the `Ember.View`'s `create` method and using the supplied block as + the view's own template. + + An empty `` and the following template: + + ```handlebars + A span: + {{#view tagName="span"}} + hello. + {{/view}} + ``` + + Will result in HTML structure: + + ```html + + + +
    + A span: + + Hello. + +
    + + ``` + + ### `parentView` setting + + The `parentView` property of the new `Ember.View` instance created through + `{{view}}` will be set to the `Ember.View` instance of the template where + `{{view}}` was called. + + ```javascript + aView = Ember.View.create({ + template: Ember.Handlebars.compile("{{#view}} my parent: {{parentView.elementId}} {{/view}}") + }); + + aView.appendTo('body'); + ``` + + Will result in HTML structure: + + ```html +
    +
    + my parent: ember1 +
    +
    + ``` + + ### Setting CSS id and class attributes + + The HTML `id` attribute can be set on the `{{view}}`'s resulting element with + the `id` option. This option will _not_ be passed to `Ember.View.create`. + + ```handlebars + {{#view tagName="span" id="a-custom-id"}} + hello. + {{/view}} + ``` + + Results in the following HTML structure: + + ```html +
    + + hello. + +
    + ``` + + The HTML `class` attribute can be set on the `{{view}}`'s resulting element + with the `class` or `classNameBindings` options. The `class` option will + directly set the CSS `class` attribute and will not be passed to + `Ember.View.create`. `classNameBindings` will be passed to `create` and use + `Ember.View`'s class name binding functionality: + + ```handlebars + {{#view tagName="span" class="a-custom-class"}} + hello. + {{/view}} + ``` + + Results in the following HTML structure: + + ```html +
    + + hello. + +
    + ``` + + ### Supplying a different view class + + `{{view}}` can take an optional first argument before its supplied options to + specify a path to a custom view class. + + ```handlebars + {{#view "custom"}}{{! will look up App.CustomView }} + hello. + {{/view}} + ``` + + The first argument can also be a relative path accessible from the current + context. + + ```javascript + MyApp = Ember.Application.create({}); + MyApp.OuterView = Ember.View.extend({ + innerViewClass: Ember.View.extend({ + classNames: ['a-custom-view-class-as-property'] + }), + template: Ember.Handlebars.compile('{{#view view.innerViewClass}} hi {{/view}}') + }); + + MyApp.OuterView.create().appendTo('body'); + ``` + + Will result in the following HTML: + + ```html +
    +
    + hi +
    +
    + ``` + + ### Blockless use + + If you supply a custom `Ember.View` subclass that specifies its own template + or provide a `templateName` option to `{{view}}` it can be used without + supplying a block. Attempts to use both a `templateName` option and supply a + block will throw an error. + + ```javascript + var App = Ember.Application.create(); + App.WithTemplateDefinedView = Ember.View.extend({ + templateName: 'defined-template' + }); + ``` + + ```handlebars + {{! application.hbs }} + {{view 'with-template-defined'}} + ``` + + ```handlebars + {{! defined-template.hbs }} + Some content for the defined template view. + ``` + + ### `viewName` property + + You can supply a `viewName` option to `{{view}}`. The `Ember.View` instance + will be referenced as a property of its parent view by this name. + + ```javascript + aView = Ember.View.create({ + template: Ember.Handlebars.compile('{{#view viewName="aChildByName"}} hi {{/view}}') + }); + + aView.appendTo('body'); + aView.get('aChildByName') // the instance of Ember.View created by {{view}} helper + ``` + + @method view + @for Ember.Handlebars.helpers + @param {String} path + @param {Hash} options + @return {String} HTML string + */ + function viewHelper(path, options) { + Ember.assert("The view helper only takes a single argument", arguments.length <= 2); + + // If no path is provided, treat path param as options + // and get an instance of the registered `view:toplevel` + if (path && path.data && path.data.isRenderData) { + options = path; + if (options.data && options.data.view && options.data.view.container) { + path = options.data.view.container.lookupFactory('view:toplevel'); + } else { + path = View; + } + } + + options.helperName = options.helperName || 'view'; + + return ViewHelper.helper(this, path, options); + } + + __exports__.viewHelper = viewHelper; + }); +enifed("ember-handlebars/helpers/yield", + ["ember-metal/core","ember-metal/property_get","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var Ember = __dependency1__["default"]; + // var emberAssert = Ember.assert; + + var get = __dependency2__.get; + + /** + `{{yield}}` denotes an area of a template that will be rendered inside + of another template. It has two main uses: + + ### Use with `layout` + When used in a Handlebars template that is assigned to an `Ember.View` + instance's `layout` property Ember will render the layout template first, + inserting the view's own rendered output at the `{{yield}}` location. + + An empty `` and the following application code: + + ```javascript + AView = Ember.View.extend({ + classNames: ['a-view-with-layout'], + layout: Ember.Handlebars.compile('
    {{yield}}
    '), + template: Ember.Handlebars.compile('I am wrapped') + }); + + aView = AView.create(); + aView.appendTo('body'); + ``` + + Will result in the following HTML output: + + ```html + +
    +
    + I am wrapped +
    +
    + + ``` + + The `yield` helper cannot be used outside of a template assigned to an + `Ember.View`'s `layout` property and will throw an error if attempted. + + ```javascript + BView = Ember.View.extend({ + classNames: ['a-view-with-layout'], + template: Ember.Handlebars.compile('{{yield}}') + }); + + bView = BView.create(); + bView.appendTo('body'); + + // throws + // Uncaught Error: assertion failed: + // You called yield in a template that was not a layout + ``` + + ### Use with Ember.Component + When designing components `{{yield}}` is used to denote where, inside the component's + template, an optional block passed to the component should render: + + ```handlebars + + {{#labeled-textfield value=someProperty}} + First name: + {{/labeled-textfield}} + ``` + + ```handlebars + + + ``` + + Result: + + ```html + + ``` + + @method yield + @for Ember.Handlebars.helpers + @param {Hash} options + @return {String} HTML string + */ + __exports__["default"] = function yieldHelper(options) { + var view = options.data.view; + + while (view && !get(view, 'layout')) { + if (view._contextView) { + view = view._contextView; + } else { + view = get(view, '_parentView'); + } + } + + Ember.assert("You called yield in a template that was not a layout", !!view); + + view._yield(this, options); + } + }); +enifed("ember-handlebars/loader", + ["ember-handlebars/component_lookup","ember-views/system/jquery","ember-metal/error","ember-runtime/system/lazy_load","ember-handlebars-compiler","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + /*globals Handlebars */ + + var ComponentLookup = __dependency1__["default"]; + var jQuery = __dependency2__["default"]; + var EmberError = __dependency3__["default"]; + var onLoad = __dependency4__.onLoad; + + var EmberHandlebars = __dependency5__["default"]; + + /** + @module ember + @submodule ember-handlebars + */ + + /** + Find templates stored in the head tag as script tags and make them available + to `Ember.CoreView` in the global `Ember.TEMPLATES` object. This will be run + as as jQuery DOM-ready callback. + + Script tags with `text/x-handlebars` will be compiled + with Ember's Handlebars and are suitable for use as a view's template. + Those with type `text/x-raw-handlebars` will be compiled with regular + Handlebars and are suitable for use in views' computed properties. + + @private + @method bootstrap + @for Ember.Handlebars + @static + @param ctx + */ + function bootstrap(ctx) { + var selectors = 'script[type="text/x-handlebars"], script[type="text/x-raw-handlebars"]'; + + jQuery(selectors, ctx) + .each(function() { + // Get a reference to the script tag + var script = jQuery(this); + + var compile = (script.attr('type') === 'text/x-raw-handlebars') ? + jQuery.proxy(Handlebars.compile, Handlebars) : + jQuery.proxy(EmberHandlebars.compile, EmberHandlebars); + // Get the name of the script, used by Ember.View's templateName property. + // First look for data-template-name attribute, then fall back to its + // id if no name is found. + var templateName = script.attr('data-template-name') || script.attr('id') || 'application'; + var template = compile(script.html()); + + // Check if template of same name already exists + if (Ember.TEMPLATES[templateName] !== undefined) { + throw new EmberError('Template named "' + templateName + '" already exists.'); + } + + // For templates which have a name, we save them and then remove them from the DOM + Ember.TEMPLATES[templateName] = template; + + // Remove script tag from DOM + script.remove(); + }); + } + + function _bootstrap() { + bootstrap( jQuery(document) ); + } + + function registerComponentLookup(container) { + container.register('component-lookup:main', ComponentLookup); + } + + /* + We tie this to application.load to ensure that we've at least + attempted to bootstrap at the point that the application is loaded. + + We also tie this to document ready since we're guaranteed that all + the inline templates are present at this point. + + There's no harm to running this twice, since we remove the templates + from the DOM after processing. + */ + + onLoad('Ember.Application', function(Application) { + Application.initializer({ + name: 'domTemplates', + initialize: _bootstrap + }); + + Application.initializer({ + name: 'registerComponentLookup', + after: 'domTemplates', + initialize: registerComponentLookup + }); + }); + + __exports__["default"] = bootstrap; + }); +enifed("ember-handlebars/string", + ["ember-runtime/system/string","exports"], + function(__dependency1__, __exports__) { + "use strict"; + // required so we can extend this object. + var EmberStringUtils = __dependency1__["default"]; + + /** + Mark a string as safe for unescaped output with Handlebars. If you + return HTML from a Handlebars helper, use this function to + ensure Handlebars does not escape the HTML. + + ```javascript + Ember.String.htmlSafe('
    someString
    ') + ``` + + @method htmlSafe + @for Ember.String + @static + @return {Handlebars.SafeString} a string that will not be html escaped by Handlebars + */ + function htmlSafe(str) { + return new Handlebars.SafeString(str); + } + + EmberStringUtils.htmlSafe = htmlSafe; + if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) { + + /** + Mark a string as being safe for unescaped output with Handlebars. + + ```javascript + '
    someString
    '.htmlSafe() + ``` + + See [Ember.String.htmlSafe](/api/classes/Ember.String.html#method_htmlSafe). + + @method htmlSafe + @for String + @return {Handlebars.SafeString} a string that will not be html escaped by Handlebars + */ + String.prototype.htmlSafe = function() { + return htmlSafe(this); + }; + } + + __exports__["default"] = htmlSafe; + }); +enifed("ember-handlebars/views/handlebars_bound_view", + ["ember-handlebars-compiler","ember-metal/core","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/merge","ember-metal/run_loop","ember-metal/computed","ember-views/views/view","ember-views/views/states","ember-handlebars/views/metamorph_view","ember-handlebars/ext","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __exports__) { + "use strict"; + /*globals Handlebars, Metamorph:true */ + /*jshint newcap:false*/ + + + /** + @module ember + @submodule ember-handlebars + */ + + var EmberHandlebars = __dependency1__["default"]; + // EmberHandlebars.SafeString; + var SafeString = EmberHandlebars.SafeString; + + var Ember = __dependency2__["default"]; + // Ember.K + var K = Ember.K; + + var EmberError = __dependency3__["default"]; + var get = __dependency4__.get; + var set = __dependency5__.set; + var merge = __dependency6__["default"]; + var run = __dependency7__["default"]; + var computed = __dependency8__.computed; + var View = __dependency9__["default"]; + var cloneStates = __dependency10__.cloneStates; + var states = __dependency10__.states; + var viewStates = states; + + var _MetamorphView = __dependency11__["default"]; + var handlebarsGet = __dependency12__.handlebarsGet; + var uuid = __dependency13__.uuid; + + function SimpleHandlebarsView(path, pathRoot, isEscaped, templateData) { + this.path = path; + this.pathRoot = pathRoot; + this.isEscaped = isEscaped; + this.templateData = templateData; + this[Ember.GUID_KEY] = uuid(); + this._lastNormalizedValue = undefined; + this.state = 'preRender'; + this.updateId = null; + this._parentView = null; + this.buffer = null; + this._morph = null; + } + + SimpleHandlebarsView.prototype = { + isVirtual: true, + isView: true, + + destroy: function () { + if (this.updateId) { + run.cancel(this.updateId); + this.updateId = null; + } + if (this._parentView) { + this._parentView.removeChild(this); + } + this.morph = null; + this.state = 'destroyed'; + }, + + propertyWillChange: K, + + propertyDidChange: K, + + normalizedValue: function() { + var path = this.path; + var pathRoot = this.pathRoot; + var escape = this.isEscaped; + var result, templateData; + + // Use the pathRoot as the result if no path is provided. This + // happens if the path is `this`, which gets normalized into + // a `pathRoot` of the current Handlebars context and a path + // of `''`. + if (path === '') { + result = pathRoot; + } else { + templateData = this.templateData; + result = handlebarsGet(pathRoot, path, { data: templateData }); + } + + if (!escape && !(result instanceof SafeString)) { + result = new SafeString(result); + } + + return result; + }, + + render: function(buffer) { + var value = this.normalizedValue(); + this._lastNormalizedValue = value; + buffer._element = value; + }, + + rerender: function() { + switch(this.state) { + case 'preRender': + case 'destroyed': + break; + case 'inBuffer': + throw new EmberError("Something you did tried to replace an {{expression}} before it was inserted into the DOM."); + case 'hasElement': + case 'inDOM': + this.updateId = run.scheduleOnce('render', this, 'update'); + break; + } + return this; + }, + + update: function () { + this.updateId = null; + var value = this.normalizedValue(); + // doesn't diff SafeString instances + if (value !== this._lastNormalizedValue) { + this._lastNormalizedValue = value; + this._morph.update(value); + } + }, + + _transitionTo: function(state) { + this.state = state; + } + }; + + states = cloneStates(viewStates); + + merge(states._default, { + rerenderIfNeeded: K + }); + + merge(states.inDOM, { + rerenderIfNeeded: function(view) { + if (view.normalizedValue() !== view._lastNormalizedValue) { + view.rerender(); + } + } + }); + + /** + `Ember._HandlebarsBoundView` is a private view created by the Handlebars + `{{bind}}` helpers that is used to keep track of bound properties. + + Every time a property is bound using a `{{mustache}}`, an anonymous subclass + of `Ember._HandlebarsBoundView` is created with the appropriate sub-template + and context set up. When the associated property changes, just the template + for this view will re-render. + + @class _HandlebarsBoundView + @namespace Ember + @extends Ember._MetamorphView + @private + */ + var _HandlebarsBoundView = _MetamorphView.extend({ + instrumentName: 'boundHandlebars', + + _states: states, + + /** + The function used to determine if the `displayTemplate` or + `inverseTemplate` should be rendered. This should be a function that takes + a value and returns a Boolean. + + @property shouldDisplayFunc + @type Function + @default null + */ + shouldDisplayFunc: null, + + /** + Whether the template rendered by this view gets passed the context object + of its parent template, or gets passed the value of retrieving `path` + from the `pathRoot`. + + For example, this is true when using the `{{#if}}` helper, because the + template inside the helper should look up properties relative to the same + object as outside the block. This would be `false` when used with `{{#with + foo}}` because the template should receive the object found by evaluating + `foo`. + + @property preserveContext + @type Boolean + @default false + */ + preserveContext: false, + + /** + If `preserveContext` is true, this is the object that will be used + to render the template. + + @property previousContext + @type Object + */ + previousContext: null, + + /** + The template to render when `shouldDisplayFunc` evaluates to `true`. + + @property displayTemplate + @type Function + @default null + */ + displayTemplate: null, + + /** + The template to render when `shouldDisplayFunc` evaluates to `false`. + + @property inverseTemplate + @type Function + @default null + */ + inverseTemplate: null, + + + /** + The path to look up on `pathRoot` that is passed to + `shouldDisplayFunc` to determine which template to render. + + In addition, if `preserveContext` is `false,` the object at this path will + be passed to the template when rendering. + + @property path + @type String + @default null + */ + path: null, + + /** + The object from which the `path` will be looked up. Sometimes this is the + same as the `previousContext`, but in cases where this view has been + generated for paths that start with a keyword such as `view` or + `controller`, the path root will be that resolved object. + + @property pathRoot + @type Object + */ + pathRoot: null, + + normalizedValue: function() { + var path = get(this, 'path'); + var pathRoot = get(this, 'pathRoot'); + var valueNormalizer = get(this, 'valueNormalizerFunc'); + var result, templateData; + + // Use the pathRoot as the result if no path is provided. This + // happens if the path is `this`, which gets normalized into + // a `pathRoot` of the current Handlebars context and a path + // of `''`. + if (path === '') { + result = pathRoot; + } else { + templateData = get(this, 'templateData'); + result = handlebarsGet(pathRoot, path, { data: templateData }); + } + + return valueNormalizer ? valueNormalizer(result) : result; + }, + + rerenderIfNeeded: function() { + this.currentState.rerenderIfNeeded(this); + }, + + /** + Determines which template to invoke, sets up the correct state based on + that logic, then invokes the default `Ember.View` `render` implementation. + + This method will first look up the `path` key on `pathRoot`, + then pass that value to the `shouldDisplayFunc` function. If that returns + `true,` the `displayTemplate` function will be rendered to DOM. Otherwise, + `inverseTemplate`, if specified, will be rendered. + + For example, if this `Ember._HandlebarsBoundView` represented the `{{#with + foo}}` helper, it would look up the `foo` property of its context, and + `shouldDisplayFunc` would always return true. The object found by looking + up `foo` would be passed to `displayTemplate`. + + @method render + @param {Ember.RenderBuffer} buffer + */ + render: function(buffer) { + // If not invoked via a triple-mustache ({{{foo}}}), escape + // the content of the template. + var escape = get(this, 'isEscaped'); + + var shouldDisplay = get(this, 'shouldDisplayFunc'); + var preserveContext = get(this, 'preserveContext'); + var context = get(this, 'previousContext'); + + var inverseTemplate = get(this, 'inverseTemplate'); + var displayTemplate = get(this, 'displayTemplate'); + + var result = this.normalizedValue(); + + this._lastNormalizedValue = result; + + // First, test the conditional to see if we should + // render the template or not. + if (shouldDisplay(result)) { + set(this, 'template', displayTemplate); + + // If we are preserving the context (for example, if this + // is an #if block, call the template with the same object. + if (preserveContext) { + set(this, '_context', context); + } else { + // Otherwise, determine if this is a block bind or not. + // If so, pass the specified object to the template + if (displayTemplate) { + set(this, '_context', result); + } else { + // This is not a bind block, just push the result of the + // expression to the render context and return. + if (result === null || result === undefined) { + result = ""; + } else if (!(result instanceof SafeString)) { + result = String(result); + } + + if (escape) { result = Handlebars.Utils.escapeExpression(result); } + buffer.push(result); + return; + } + } + } else if (inverseTemplate) { + set(this, 'template', inverseTemplate); + + if (preserveContext) { + set(this, '_context', context); + } else { + set(this, '_context', result); + } + } else { + set(this, 'template', function() { return ''; }); + } + + return this._super(buffer); + } + }); + + __exports__._HandlebarsBoundView = _HandlebarsBoundView; + __exports__.SimpleHandlebarsView = SimpleHandlebarsView; + }); +enifed("ember-handlebars/views/metamorph_view", + ["ember-metal/core","ember-views/views/core_view","ember-views/views/view","ember-metal/mixin","ember-metal/run_loop","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + /* global Metamorph:true */ + + /*jshint newcap:false*/ + var Ember = __dependency1__["default"]; + // Ember.deprecate + + var CoreView = __dependency2__["default"]; + var View = __dependency3__["default"]; + var Mixin = __dependency4__.Mixin; + var run = __dependency5__["default"]; + + /** + @module ember + @submodule ember-handlebars + */ + + function notifyMutationListeners() { + run.once(View, 'notifyMutationListeners'); + } + + // The `morph` and `outerHTML` properties are internal only + // and not observable. + + /** + @class _Metamorph + @namespace Ember + @private + */ + var _Metamorph = Mixin.create({ + isVirtual: true, + tagName: '', + + instrumentName: 'metamorph', + + init: function() { + this._super(); + Ember.deprecate('Supplying a tagName to Metamorph views is unreliable and is deprecated. You may be setting the tagName on a Handlebars helper that creates a Metamorph.', !this.tagName); + } + }); + __exports__._Metamorph = _Metamorph; + /** + @class _MetamorphView + @namespace Ember + @extends Ember.View + @uses Ember._Metamorph + @private + */ + var _MetamorphView = View.extend(_Metamorph); + __exports__._MetamorphView = _MetamorphView; + /** + @class _SimpleMetamorphView + @namespace Ember + @extends Ember.CoreView + @uses Ember._Metamorph + @private + */ + var _SimpleMetamorphView = CoreView.extend(_Metamorph); + __exports__._SimpleMetamorphView = _SimpleMetamorphView;__exports__["default"] = View.extend(_Metamorph); + }); +enifed("ember-metal-views", + ["ember-metal-views/renderer","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Renderer = __dependency1__["default"]; + __exports__.Renderer = Renderer; + }); +enifed("ember-metal-views/renderer", + ["morph","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var DOMHelper = __dependency1__.DOMHelper; + + function Renderer() { + this._uuid = 0; + this._views = new Array(2000); + this._queue = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; + this._parents = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; + this._elements = new Array(17); + this._inserts = {}; + this._dom = new DOMHelper(); + } + + function Renderer_renderTree(_view, _parentView, _insertAt) { + var views = this._views; + views[0] = _view; + var insertAt = _insertAt === undefined ? -1 : _insertAt; + var index = 0; + var total = 1; + var levelBase = _parentView ? _parentView._level+1 : 0; + + var root = _parentView == null ? _view : _parentView._root; + + // if root view has a _morph assigned + var willInsert = !!root._morph; + + var queue = this._queue; + queue[0] = 0; + var length = 1; + + var parentIndex = -1; + var parents = this._parents; + var parent = _parentView || null; + var elements = this._elements; + var element = null; + var contextualElement = null; + var level = 0; + + var view = _view; + var children, i, l, child; + while (length) { + elements[level] = element; + if (!view._morph) { + // ensure props we add are in same order + view._morph = null; + } + view._root = root; + this.uuid(view); + view._level = levelBase + level; + if (view._elementCreated) { + this.remove(view, false, true); + } + + this.willCreateElement(view); + + contextualElement = view._morph && view._morph.contextualElement; + if (!contextualElement && parent && parent._childViewsMorph) { + contextualElement = parent._childViewsMorph.contextualElement; + } + if (!contextualElement && view._didCreateElementWithoutMorph) { + // This code path is only used by createElement and rerender when createElement + // was previously called on a view. + contextualElement = document.body; + } + Ember.assert("Required contextualElement for view "+_view+" is missing", contextualElement); + element = this.createElement(view, contextualElement); + + parents[level++] = parentIndex; + parentIndex = index; + parent = view; + + // enqueue for end + queue[length++] = index; + // enqueue children + children = this.childViews(view); + if (children) { + for (i=children.length-1;i>=0;i--) { + child = children[i]; + index = total++; + views[index] = child; + queue[length++] = index; + view = child; + } + } + + index = queue[--length]; + view = views[index]; + + while (parentIndex === index) { + level--; + view._elementCreated = true; + this.didCreateElement(view); + if (willInsert) { + this.willInsertElement(view); + } + + if (level === 0) { + length--; + break; + } + + parentIndex = parents[level]; + parent = parentIndex === -1 ? _parentView : views[parentIndex]; + this.insertElement(view, parent, element, -1); + index = queue[--length]; + view = views[index]; + element = elements[level]; + elements[level] = null; + } + } + + this.insertElement(view, _parentView, element, insertAt); + + for (i=total-1;i>=0;i--) { + if (willInsert) { + views[i]._elementInserted = true; + this.didInsertElement(views[i]); + } + views[i] = null; + } + + return element; + } + + Renderer.prototype.uuid = function Renderer_uuid(view) { + if (view._uuid === undefined) { + view._uuid = ++this._uuid; + view._renderer = this; + } // else assert(view._renderer === this) + return view._uuid; + }; + + Renderer.prototype.scheduleInsert = + function Renderer_scheduleInsert(view, morph) { + if (view._morph || view._elementCreated) { + throw new Error("You cannot insert a View that has already been rendered"); + } + Ember.assert("You cannot insert a View without a morph", morph); + view._morph = morph; + var viewId = this.uuid(view); + this._inserts[viewId] = this.scheduleRender(this, function() { + this._inserts[viewId] = null; + this.renderTree(view); + }); + }; + + Renderer.prototype.appendTo = + function Renderer_appendTo(view, target) { + var morph = this._dom.appendMorph(target); + this.scheduleInsert(view, morph); + }; + + Renderer.prototype.replaceIn = + function Renderer_replaceIn(view, target) { + var morph = this._dom.createMorph(target, null, null); + this.scheduleInsert(view, morph); + }; + + function Renderer_remove(_view, shouldDestroy, reset) { + var viewId = this.uuid(_view); + + if (this._inserts[viewId]) { + this.cancelRender(this._inserts[viewId]); + this._inserts[viewId] = undefined; + } + + if (!_view._elementCreated) { + return; + } + + var removeQueue = []; + var destroyQueue = []; + var morph = _view._morph; + var idx, len, view, staticChildren, queue, + childViews, i, l, parentView; + + removeQueue.push(_view); + + for (idx=0; idx -1; + }; + + var defineNativeShim = function(nativeFunc, shim) { + if (isNativeFunc(nativeFunc)) { + return nativeFunc; + } + return shim; + }; + + // From: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/map + var map = defineNativeShim(ArrayPrototype.map, function(fun /*, thisp */) { + //"use strict"; + + if (this === void 0 || this === null || typeof fun !== "function") { + throw new TypeError(); + } + + var t = Object(this); + var len = t.length >>> 0; + var res = new Array(len); + var thisp = arguments[1]; + + for (var i = 0; i < len; i++) { + if (i in t) { + res[i] = fun.call(thisp, t[i], i, t); + } + } + + return res; + }); + + // From: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/foreach + var forEach = defineNativeShim(ArrayPrototype.forEach, function(fun /*, thisp */) { + //"use strict"; + + if (this === void 0 || this === null || typeof fun !== "function") { + throw new TypeError(); + } + + var t = Object(this); + var len = t.length >>> 0; + var thisp = arguments[1]; + + for (var i = 0; i < len; i++) { + if (i in t) { + fun.call(thisp, t[i], i, t); + } + } + }); + + var indexOf = defineNativeShim(ArrayPrototype.indexOf, function (obj, fromIndex) { + if (fromIndex === null || fromIndex === undefined) { + fromIndex = 0; + } + else if (fromIndex < 0) { + fromIndex = Math.max(0, this.length + fromIndex); + } + + for (var i = fromIndex, j = this.length; i < j; i++) { + if (this[i] === obj) { + return i; + } + } + return -1; + }); + + var lastIndexOf = defineNativeShim(ArrayPrototype.lastIndexOf, function(obj, fromIndex) { + var len = this.length; + var idx; + + if (fromIndex === undefined) fromIndex = len-1; + else fromIndex = (fromIndex < 0) ? Math.ceil(fromIndex) : Math.floor(fromIndex); + if (fromIndex < 0) fromIndex += len; + + for(idx = fromIndex;idx>=0;idx--) { + if (this[idx] === obj) return idx ; + } + return -1; + }); + + var filter = defineNativeShim(ArrayPrototype.filter, function (fn, context) { + var i, value; + var result = []; + var length = this.length; + + for (i = 0; i < length; i++) { + if (this.hasOwnProperty(i)) { + value = this[i]; + if (fn.call(context, value, i, this)) { + result.push(value); + } + } + } + return result; + }); + + if (Ember.SHIM_ES5) { + ArrayPrototype.map = ArrayPrototype.map || map; + ArrayPrototype.forEach = ArrayPrototype.forEach || forEach; + ArrayPrototype.filter = ArrayPrototype.filter || filter; + ArrayPrototype.indexOf = ArrayPrototype.indexOf || indexOf; + ArrayPrototype.lastIndexOf = ArrayPrototype.lastIndexOf || lastIndexOf; + } + + /** + Array polyfills to support ES5 features in older browsers. + + @namespace Ember + @property ArrayPolyfills + */ + __exports__.map = map; + __exports__.forEach = forEach; + __exports__.filter = filter; + __exports__.indexOf = indexOf; + __exports__.lastIndexOf = lastIndexOf; + }); +enifed("ember-metal/binding", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/observer","ember-metal/run_loop","ember-metal/path_cache","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.Logger, Ember.LOG_BINDINGS, assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var trySet = __dependency3__.trySet; + var guidFor = __dependency4__.guidFor; + var addObserver = __dependency5__.addObserver; + var removeObserver = __dependency5__.removeObserver; + var _suspendObserver = __dependency5__._suspendObserver; + var run = __dependency6__["default"]; + var isGlobalPath = __dependency7__.isGlobal; + + + // ES6TODO: where is Ember.lookup defined? + /** + @module ember-metal + */ + + // .......................................................... + // CONSTANTS + // + + /** + Debug parameter you can turn on. This will log all bindings that fire to + the console. This should be disabled in production code. Note that you + can also enable this from the console or temporarily. + + @property LOG_BINDINGS + @for Ember + @type Boolean + @default false + */ + Ember.LOG_BINDINGS = false || !!Ember.ENV.LOG_BINDINGS; + + /** + Returns true if the provided path is global (e.g., `MyApp.fooController.bar`) + instead of local (`foo.bar.baz`). + + @method isGlobalPath + @for Ember + @private + @param {String} path + @return Boolean + */ + + function getWithGlobals(obj, path) { + return get(isGlobalPath(path) ? Ember.lookup : obj, path); + } + + // .......................................................... + // BINDING + // + + function Binding(toPath, fromPath) { + this._direction = undefined; + this._from = fromPath; + this._to = toPath; + this._readyToSync = undefined; + this._oneWay = undefined; + } + + /** + @class Binding + @namespace Ember + */ + + Binding.prototype = { + /** + This copies the Binding so it can be connected to another object. + + @method copy + @return {Ember.Binding} `this` + */ + copy: function () { + var copy = new Binding(this._to, this._from); + if (this._oneWay) { copy._oneWay = true; } + return copy; + }, + + // .......................................................... + // CONFIG + // + + /** + This will set `from` property path to the specified value. It will not + attempt to resolve this property path to an actual object until you + connect the binding. + + The binding will search for the property path starting at the root object + you pass when you `connect()` the binding. It follows the same rules as + `get()` - see that method for more information. + + @method from + @param {String} path the property path to connect to + @return {Ember.Binding} `this` + */ + from: function(path) { + this._from = path; + return this; + }, + + /** + This will set the `to` property path to the specified value. It will not + attempt to resolve this property path to an actual object until you + connect the binding. + + The binding will search for the property path starting at the root object + you pass when you `connect()` the binding. It follows the same rules as + `get()` - see that method for more information. + + @method to + @param {String|Tuple} path A property path or tuple + @return {Ember.Binding} `this` + */ + to: function(path) { + this._to = path; + return this; + }, + + /** + Configures the binding as one way. A one-way binding will relay changes + on the `from` side to the `to` side, but not the other way around. This + means that if you change the `to` side directly, the `from` side may have + a different value. + + @method oneWay + @return {Ember.Binding} `this` + */ + oneWay: function() { + this._oneWay = true; + return this; + }, + + /** + @method toString + @return {String} string representation of binding + */ + toString: function() { + var oneWay = this._oneWay ? '[oneWay]' : ''; + return "Ember.Binding<" + guidFor(this) + ">(" + this._from + " -> " + this._to + ")" + oneWay; + }, + + // .......................................................... + // CONNECT AND SYNC + // + + /** + Attempts to connect this binding instance so that it can receive and relay + changes. This method will raise an exception if you have not set the + from/to properties yet. + + @method connect + @param {Object} obj The root object for this binding. + @return {Ember.Binding} `this` + */ + connect: function(obj) { + Ember.assert('Must pass a valid object to Ember.Binding.connect()', !!obj); + + var fromPath = this._from; + var toPath = this._to; + trySet(obj, toPath, getWithGlobals(obj, fromPath)); + + // add an observer on the object to be notified when the binding should be updated + addObserver(obj, fromPath, this, this.fromDidChange); + + // if the binding is a two-way binding, also set up an observer on the target + if (!this._oneWay) { addObserver(obj, toPath, this, this.toDidChange); } + + this._readyToSync = true; + + return this; + }, + + /** + Disconnects the binding instance. Changes will no longer be relayed. You + will not usually need to call this method. + + @method disconnect + @param {Object} obj The root object you passed when connecting the binding. + @return {Ember.Binding} `this` + */ + disconnect: function(obj) { + Ember.assert('Must pass a valid object to Ember.Binding.disconnect()', !!obj); + + var twoWay = !this._oneWay; + + // remove an observer on the object so we're no longer notified of + // changes that should update bindings. + removeObserver(obj, this._from, this, this.fromDidChange); + + // if the binding is two-way, remove the observer from the target as well + if (twoWay) { removeObserver(obj, this._to, this, this.toDidChange); } + + this._readyToSync = false; // disable scheduled syncs... + return this; + }, + + // .......................................................... + // PRIVATE + // + + /* called when the from side changes */ + fromDidChange: function(target) { + this._scheduleSync(target, 'fwd'); + }, + + /* called when the to side changes */ + toDidChange: function(target) { + this._scheduleSync(target, 'back'); + }, + + _scheduleSync: function(obj, dir) { + var existingDir = this._direction; + + // if we haven't scheduled the binding yet, schedule it + if (existingDir === undefined) { + run.schedule('sync', this, this._sync, obj); + this._direction = dir; + } + + // If both a 'back' and 'fwd' sync have been scheduled on the same object, + // default to a 'fwd' sync so that it remains deterministic. + if (existingDir === 'back' && dir === 'fwd') { + this._direction = 'fwd'; + } + }, + + _sync: function(obj) { + var log = Ember.LOG_BINDINGS; + + // don't synchronize destroyed objects or disconnected bindings + if (obj.isDestroyed || !this._readyToSync) { return; } + + // get the direction of the binding for the object we are + // synchronizing from + var direction = this._direction; + + var fromPath = this._from; + var toPath = this._to; + + this._direction = undefined; + + // if we're synchronizing from the remote object... + if (direction === 'fwd') { + var fromValue = getWithGlobals(obj, this._from); + if (log) { + Ember.Logger.log(' ', this.toString(), '->', fromValue, obj); + } + if (this._oneWay) { + trySet(obj, toPath, fromValue); + } else { + _suspendObserver(obj, toPath, this, this.toDidChange, function () { + trySet(obj, toPath, fromValue); + }); + } + // if we're synchronizing *to* the remote object + } else if (direction === 'back') { + var toValue = get(obj, this._to); + if (log) { + Ember.Logger.log(' ', this.toString(), '<-', toValue, obj); + } + _suspendObserver(obj, fromPath, this, this.fromDidChange, function () { + trySet(isGlobalPath(fromPath) ? Ember.lookup : obj, fromPath, toValue); + }); + } + } + + }; + + function mixinProperties(to, from) { + for (var key in from) { + if (from.hasOwnProperty(key)) { + to[key] = from[key]; + } + } + } + + mixinProperties(Binding, { + + /* + See `Ember.Binding.from`. + + @method from + @static + */ + from: function(from) { + var C = this; + return new C(undefined, from); + }, + + /* + See `Ember.Binding.to`. + + @method to + @static + */ + to: function(to) { + var C = this; + return new C(to, undefined); + }, + + /** + Creates a new Binding instance and makes it apply in a single direction. + A one-way binding will relay changes on the `from` side object (supplied + as the `from` argument) the `to` side, but not the other way around. + This means that if you change the "to" side directly, the "from" side may have + a different value. + + See `Binding.oneWay`. + + @method oneWay + @param {String} from from path. + @param {Boolean} [flag] (Optional) passing nothing here will make the + binding `oneWay`. You can instead pass `false` to disable `oneWay`, making the + binding two way again. + @return {Ember.Binding} `this` + */ + oneWay: function(from, flag) { + var C = this; + return new C(undefined, from).oneWay(flag); + } + + }); + /** + An `Ember.Binding` connects the properties of two objects so that whenever + the value of one property changes, the other property will be changed also. + + ## Automatic Creation of Bindings with `/^*Binding/`-named Properties + + You do not usually create Binding objects directly but instead describe + bindings in your class or object definition using automatic binding + detection. + + Properties ending in a `Binding` suffix will be converted to `Ember.Binding` + instances. The value of this property should be a string representing a path + to another object or a custom binding instance created using Binding helpers + (see "One Way Bindings"): + + ``` + valueBinding: "MyApp.someController.title" + ``` + + This will create a binding from `MyApp.someController.title` to the `value` + property of your object instance automatically. Now the two values will be + kept in sync. + + ## One Way Bindings + + One especially useful binding customization you can use is the `oneWay()` + helper. This helper tells Ember that you are only interested in + receiving changes on the object you are binding from. For example, if you + are binding to a preference and you want to be notified if the preference + has changed, but your object will not be changing the preference itself, you + could do: + + ``` + bigTitlesBinding: Ember.Binding.oneWay("MyApp.preferencesController.bigTitles") + ``` + + This way if the value of `MyApp.preferencesController.bigTitles` changes the + `bigTitles` property of your object will change also. However, if you + change the value of your `bigTitles` property, it will not update the + `preferencesController`. + + One way bindings are almost twice as fast to setup and twice as fast to + execute because the binding only has to worry about changes to one side. + + You should consider using one way bindings anytime you have an object that + may be created frequently and you do not intend to change a property; only + to monitor it for changes (such as in the example above). + + ## Adding Bindings Manually + + All of the examples above show you how to configure a custom binding, but the + result of these customizations will be a binding template, not a fully active + Binding instance. The binding will actually become active only when you + instantiate the object the binding belongs to. It is useful however, to + understand what actually happens when the binding is activated. + + For a binding to function it must have at least a `from` property and a `to` + property. The `from` property path points to the object/key that you want to + bind from while the `to` path points to the object/key you want to bind to. + + When you define a custom binding, you are usually describing the property + you want to bind from (such as `MyApp.someController.value` in the examples + above). When your object is created, it will automatically assign the value + you want to bind `to` based on the name of your binding key. In the + examples above, during init, Ember objects will effectively call + something like this on your binding: + + ```javascript + binding = Ember.Binding.from("valueBinding").to("value"); + ``` + + This creates a new binding instance based on the template you provide, and + sets the to path to the `value` property of the new object. Now that the + binding is fully configured with a `from` and a `to`, it simply needs to be + connected to become active. This is done through the `connect()` method: + + ```javascript + binding.connect(this); + ``` + + Note that when you connect a binding you pass the object you want it to be + connected to. This object will be used as the root for both the from and + to side of the binding when inspecting relative paths. This allows the + binding to be automatically inherited by subclassed objects as well. + + This also allows you to bind between objects using the paths you declare in + `from` and `to`: + + ```javascript + // Example 1 + binding = Ember.Binding.from("App.someObject.value").to("value"); + binding.connect(this); + + // Example 2 + binding = Ember.Binding.from("parentView.value").to("App.someObject.value"); + binding.connect(this); + ``` + + Now that the binding is connected, it will observe both the from and to side + and relay changes. + + If you ever needed to do so (you almost never will, but it is useful to + understand this anyway), you could manually create an active binding by + using the `Ember.bind()` helper method. (This is the same method used by + to setup your bindings on objects): + + ```javascript + Ember.bind(MyApp.anotherObject, "value", "MyApp.someController.value"); + ``` + + Both of these code fragments have the same effect as doing the most friendly + form of binding creation like so: + + ```javascript + MyApp.anotherObject = Ember.Object.create({ + valueBinding: "MyApp.someController.value", + + // OTHER CODE FOR THIS OBJECT... + }); + ``` + + Ember's built in binding creation method makes it easy to automatically + create bindings for you. You should always use the highest-level APIs + available, even if you understand how it works underneath. + + @class Binding + @namespace Ember + @since Ember 0.9 + */ + // Ember.Binding = Binding; ES6TODO: where to put this? + + + /** + Global helper method to create a new binding. Just pass the root object + along with a `to` and `from` path to create and connect the binding. + + @method bind + @for Ember + @param {Object} obj The root object of the transform. + @param {String} to The path to the 'to' side of the binding. + Must be relative to obj. + @param {String} from The path to the 'from' side of the binding. + Must be relative to obj or a global path. + @return {Ember.Binding} binding instance + */ + function bind(obj, to, from) { + return new Binding(to, from).connect(obj); + } + + __exports__.bind = bind;/** + @method oneWay + @for Ember + @param {Object} obj The root object of the transform. + @param {String} to The path to the 'to' side of the binding. + Must be relative to obj. + @param {String} from The path to the 'from' side of the binding. + Must be relative to obj or a global path. + @return {Ember.Binding} binding instance + */ + function oneWay(obj, to, from) { + return new Binding(to, from).oneWay().connect(obj); + } + + __exports__.oneWay = oneWay;__exports__.Binding = Binding; + __exports__.isGlobalPath = isGlobalPath; + }); +enifed("ember-metal/cache", + ["ember-metal/dictionary","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var dictionary = __dependency1__["default"]; + __exports__["default"] = Cache; + + function Cache(limit, func) { + this.store = dictionary(null); + this.size = 0; + this.misses = 0; + this.hits = 0; + this.limit = limit; + this.func = func; + } + + var FALSE = function() { }; + var ZERO = function() { }; + var UNDEFINED = function() { }; + var NULL = function() { }; + + Cache.prototype = { + set: function(key, value) { + if (this.limit > this.size) { + this.size ++; + if (value === undefined) { + this.store[key] = UNDEFINED; + } else { + this.store[key] = value; + } + } + + return value; + }, + + get: function(key) { + var value = this.store[key]; + + if (value === undefined) { + this.misses ++; + value = this.set(key, this.func(key)); + } else if (value === UNDEFINED) { + this.hits ++; + value = undefined; + } else { + this.hits ++; + // nothing to translate + } + + return value; + }, + + purge: function() { + this.store = dictionary(null); + this.size = 0; + this.hits = 0; + this.misses = 0; + } + }; + }); +enifed("ember-metal/chains", + ["ember-metal/core","ember-metal/property_get","ember-metal/utils","ember-metal/array","ember-metal/watch_key","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // warn, assert, etc; + var get = __dependency2__.get; + var normalizeTuple = __dependency2__.normalizeTuple; + var meta = __dependency3__.meta; + var forEach = __dependency4__.forEach; + var watchKey = __dependency5__.watchKey; + var unwatchKey = __dependency5__.unwatchKey; + + var metaFor = meta; + var warn = Ember.warn; + var FIRST_KEY = /^([^\.]+)/; + + function firstKey(path) { + return path.match(FIRST_KEY)[0]; + } + + var pendingQueue = []; + + // attempts to add the pendingQueue chains again. If some of them end up + // back in the queue and reschedule is true, schedules a timeout to try + // again. + function flushPendingChains() { + if (pendingQueue.length === 0) { return; } // nothing to do + + var queue = pendingQueue; + pendingQueue = []; + + forEach.call(queue, function(q) { q[0].add(q[1]); }); + + warn('Watching an undefined global, Ember expects watched globals to be setup by the time the run loop is flushed, check for typos', pendingQueue.length === 0); + } + + __exports__.flushPendingChains = flushPendingChains;function addChainWatcher(obj, keyName, node) { + if (!obj || ('object' !== typeof obj)) { return; } // nothing to do + + var m = metaFor(obj); + var nodes = m.chainWatchers; + + if (!m.hasOwnProperty('chainWatchers')) { + nodes = m.chainWatchers = {}; + } + + if (!nodes[keyName]) { nodes[keyName] = []; } + nodes[keyName].push(node); + watchKey(obj, keyName, m); + } + + function removeChainWatcher(obj, keyName, node) { + if (!obj || 'object' !== typeof obj) { return; } // nothing to do + + var m = obj['__ember_meta__']; + if (m && !m.hasOwnProperty('chainWatchers')) { return; } // nothing to do + + var nodes = m && m.chainWatchers; + + if (nodes && nodes[keyName]) { + nodes = nodes[keyName]; + for (var i = 0, l = nodes.length; i < l; i++) { + if (nodes[i] === node) { + nodes.splice(i, 1); + break; + } + } + } + unwatchKey(obj, keyName, m); + } + + // A ChainNode watches a single key on an object. If you provide a starting + // value for the key then the node won't actually watch it. For a root node + // pass null for parent and key and object for value. + function ChainNode(parent, key, value) { + this._parent = parent; + this._key = key; + + // _watching is true when calling get(this._parent, this._key) will + // return the value of this node. + // + // It is false for the root of a chain (because we have no parent) + // and for global paths (because the parent node is the object with + // the observer on it) + this._watching = value===undefined; + + this._value = value; + this._paths = {}; + if (this._watching) { + this._object = parent.value(); + if (this._object) { addChainWatcher(this._object, this._key, this); } + } + + // Special-case: the EachProxy relies on immediate evaluation to + // establish its observers. + // + // TODO: Replace this with an efficient callback that the EachProxy + // can implement. + if (this._parent && this._parent._key === '@each') { + this.value(); + } + } + + var ChainNodePrototype = ChainNode.prototype; + + function lazyGet(obj, key) { + if (!obj) return undefined; + + var meta = obj['__ember_meta__']; + // check if object meant only to be a prototype + if (meta && meta.proto === obj) return undefined; + + if (key === "@each") return get(obj, key); + + // if a CP only return cached value + var desc = meta && meta.descs[key]; + if (desc && desc._cacheable) { + if (key in meta.cache) { + return meta.cache[key]; + } else { + return undefined; + } + } + + return get(obj, key); + } + + ChainNodePrototype.value = function() { + if (this._value === undefined && this._watching) { + var obj = this._parent.value(); + this._value = lazyGet(obj, this._key); + } + return this._value; + }; + + ChainNodePrototype.destroy = function() { + if (this._watching) { + var obj = this._object; + if (obj) { removeChainWatcher(obj, this._key, this); } + this._watching = false; // so future calls do nothing + } + }; + + // copies a top level object only + ChainNodePrototype.copy = function(obj) { + var ret = new ChainNode(null, null, obj); + var paths = this._paths; + var path; + + for (path in paths) { + if (paths[path] <= 0) { continue; } // this check will also catch non-number vals. + ret.add(path); + } + return ret; + }; + + // called on the root node of a chain to setup watchers on the specified + // path. + ChainNodePrototype.add = function(path) { + var obj, tuple, key, src, paths; + + paths = this._paths; + paths[path] = (paths[path] || 0) + 1; + + obj = this.value(); + tuple = normalizeTuple(obj, path); + + // the path was a local path + if (tuple[0] && tuple[0] === obj) { + path = tuple[1]; + key = firstKey(path); + path = path.slice(key.length+1); + + // global path, but object does not exist yet. + // put into a queue and try to connect later. + } else if (!tuple[0]) { + pendingQueue.push([this, path]); + tuple.length = 0; + return; + + // global path, and object already exists + } else { + src = tuple[0]; + key = path.slice(0, 0-(tuple[1].length+1)); + path = tuple[1]; + } + + tuple.length = 0; + this.chain(key, path, src); + }; + + // called on the root node of a chain to teardown watcher on the specified + // path + ChainNodePrototype.remove = function(path) { + var obj, tuple, key, src, paths; + + paths = this._paths; + if (paths[path] > 0) { paths[path]--; } + + obj = this.value(); + tuple = normalizeTuple(obj, path); + if (tuple[0] === obj) { + path = tuple[1]; + key = firstKey(path); + path = path.slice(key.length+1); + } else { + src = tuple[0]; + key = path.slice(0, 0-(tuple[1].length+1)); + path = tuple[1]; + } + + tuple.length = 0; + this.unchain(key, path); + }; + + ChainNodePrototype.count = 0; + + ChainNodePrototype.chain = function(key, path, src) { + var chains = this._chains; + var node; + if (!chains) { chains = this._chains = {}; } + + node = chains[key]; + if (!node) { node = chains[key] = new ChainNode(this, key, src); } + node.count++; // count chains... + + // chain rest of path if there is one + if (path) { + key = firstKey(path); + path = path.slice(key.length+1); + node.chain(key, path); // NOTE: no src means it will observe changes... + } + }; + + ChainNodePrototype.unchain = function(key, path) { + var chains = this._chains; + var node = chains[key]; + + // unchain rest of path first... + if (path && path.length>1) { + key = firstKey(path); + path = path.slice(key.length+1); + node.unchain(key, path); + } + + // delete node if needed. + node.count--; + if (node.count<=0) { + delete chains[node._key]; + node.destroy(); + } + + }; + + ChainNodePrototype.willChange = function(events) { + var chains = this._chains; + if (chains) { + for(var key in chains) { + if (!chains.hasOwnProperty(key)) { continue; } + chains[key].willChange(events); + } + } + + if (this._parent) { this._parent.chainWillChange(this, this._key, 1, events); } + }; + + ChainNodePrototype.chainWillChange = function(chain, path, depth, events) { + if (this._key) { path = this._key + '.' + path; } + + if (this._parent) { + this._parent.chainWillChange(this, path, depth+1, events); + } else { + if (depth > 1) { + events.push(this.value(), path); + } + path = 'this.' + path; + if (this._paths[path] > 0) { + events.push(this.value(), path); + } + } + }; + + ChainNodePrototype.chainDidChange = function(chain, path, depth, events) { + if (this._key) { path = this._key + '.' + path; } + if (this._parent) { + this._parent.chainDidChange(this, path, depth+1, events); + } else { + if (depth > 1) { + events.push(this.value(), path); + } + path = 'this.' + path; + if (this._paths[path] > 0) { + events.push(this.value(), path); + } + } + }; + + ChainNodePrototype.didChange = function(events) { + // invalidate my own value first. + if (this._watching) { + var obj = this._parent.value(); + if (obj !== this._object) { + removeChainWatcher(this._object, this._key, this); + this._object = obj; + addChainWatcher(obj, this._key, this); + } + this._value = undefined; + + // Special-case: the EachProxy relies on immediate evaluation to + // establish its observers. + if (this._parent && this._parent._key === '@each') + this.value(); + } + + // then notify chains... + var chains = this._chains; + if (chains) { + for(var key in chains) { + if (!chains.hasOwnProperty(key)) { continue; } + chains[key].didChange(events); + } + } + + // if no events are passed in then we only care about the above wiring update + if (events === null) { return; } + + // and finally tell parent about my path changing... + if (this._parent) { this._parent.chainDidChange(this, this._key, 1, events); } + }; + + function finishChains(obj) { + // We only create meta if we really have to + var m = obj['__ember_meta__'], + chains, chainWatchers, chainNodes; + if (m) { + // finish any current chains node watchers that reference obj + chainWatchers = m.chainWatchers; + if (chainWatchers) { + for(var key in chainWatchers) { + if (!chainWatchers.hasOwnProperty(key)) { continue; } + chainNodes = chainWatchers[key]; + if (chainNodes) { + for (var i=0,l=chainNodes.length;i 1) { + args = a_slice.call(arguments); + func = args.pop(); + } + + if (typeof func !== "function") { + throw new EmberError("Computed Property declared without a property function"); + } + + var cp = new ComputedProperty(func); + + if (args) { + cp.property.apply(cp, args); + } + + return cp; + } + + /** + Returns the cached value for a property, if one exists. + This can be useful for peeking at the value of a computed + property that is generated lazily, without accidentally causing + it to be created. + + @method cacheFor + @for Ember + @param {Object} obj the object whose property you want to check + @param {String} key the name of the property whose cached value you want + to return + @return {Object} the cached value + */ + function cacheFor(obj, key) { + var meta = obj['__ember_meta__']; + var cache = meta && meta.cache; + var ret = cache && cache[key]; + + if (ret === UNDEFINED) { return undefined; } + return ret; + } + + cacheFor.set = function(cache, key, value) { + if (value === undefined) { + cache[key] = UNDEFINED; + } else { + cache[key] = value; + } + }; + + cacheFor.get = function(cache, key) { + var ret = cache[key]; + if (ret === UNDEFINED) { return undefined; } + return ret; + }; + + cacheFor.remove = function(cache, key) { + cache[key] = undefined; + }; + + __exports__.ComputedProperty = ComputedProperty; + __exports__.computed = computed; + __exports__.cacheFor = cacheFor; + }); +enifed("ember-metal/computed_macros", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/computed","ember-metal/is_empty","ember-metal/is_none","ember-metal/alias"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__) { + "use strict"; + var Ember = __dependency1__["default"]; + var get = __dependency2__.get; + var set = __dependency3__.set; + var computed = __dependency4__.computed; + var isEmpty = __dependency5__["default"]; + var isNone = __dependency6__.isNone; + var alias = __dependency7__.alias; + + /** + @module ember-metal + */ + + var a_slice = [].slice; + + function getProperties(self, propertyNames) { + var ret = {}; + for(var i = 0; i < propertyNames.length; i++) { + ret[propertyNames[i]] = get(self, propertyNames[i]); + } + return ret; + } + + function registerComputed(name, macro) { + computed[name] = function(dependentKey) { + var args = a_slice.call(arguments); + return computed(dependentKey, function() { + return macro.apply(this, args); + }); + }; + } + + function registerComputedWithProperties(name, macro) { + computed[name] = function() { + var properties = a_slice.call(arguments); + + var computedFunc = computed(function() { + return macro.apply(this, [getProperties(this, properties)]); + }); + + return computedFunc.property.apply(computedFunc, properties); + }; + } + + /** + A computed property that returns true if the value of the dependent + property is null, an empty string, empty array, or empty function. + + Example + + ```javascript + var ToDoList = Ember.Object.extend({ + done: Ember.computed.empty('todos') + }); + + var todoList = ToDoList.create({ + todos: ['Unit Test', 'Documentation', 'Release'] + }); + + todoList.get('done'); // false + todoList.get('todos').clear(); + todoList.get('done'); // true + ``` + + @since 1.6.0 + @method computed.empty + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which negate + the original value for property + */ + computed.empty = function (dependentKey) { + return computed(dependentKey + '.length', function () { + return isEmpty(get(this, dependentKey)); + }); + }; + + /** + A computed property that returns true if the value of the dependent + property is NOT null, an empty string, empty array, or empty function. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + hasStuff: Ember.computed.notEmpty('backpack') + }); + + var hamster = Hamster.create({ backpack: ['Food', 'Sleeping Bag', 'Tent'] }); + + hamster.get('hasStuff'); // true + hamster.get('backpack').clear(); // [] + hamster.get('hasStuff'); // false + ``` + + @method computed.notEmpty + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which returns true if + original value for property is not empty. + */ + computed.notEmpty = function(dependentKey) { + return computed(dependentKey + '.length', function () { + return !isEmpty(get(this, dependentKey)); + }); + }; + + /** + A computed property that returns true if the value of the dependent + property is null or undefined. This avoids errors from JSLint complaining + about use of ==, which can be technically confusing. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + isHungry: Ember.computed.none('food') + }); + + var hamster = Hamster.create(); + + hamster.get('isHungry'); // true + hamster.set('food', 'Banana'); + hamster.get('isHungry'); // false + hamster.set('food', null); + hamster.get('isHungry'); // true + ``` + + @method computed.none + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which + returns true if original value for property is null or undefined. + */ + registerComputed('none', function(dependentKey) { + return isNone(get(this, dependentKey)); + }); + + /** + A computed property that returns the inverse boolean value + of the original value for the dependent property. + + Example + + ```javascript + var User = Ember.Object.extend({ + isAnonymous: Ember.computed.not('loggedIn') + }); + + var user = User.create({loggedIn: false}); + + user.get('isAnonymous'); // true + user.set('loggedIn', true); + user.get('isAnonymous'); // false + ``` + + @method computed.not + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which returns + inverse of the original value for property + */ + registerComputed('not', function(dependentKey) { + return !get(this, dependentKey); + }); + + /** + A computed property that converts the provided dependent property + into a boolean value. + + ```javascript + var Hamster = Ember.Object.extend({ + hasBananas: Ember.computed.bool('numBananas') + }); + + var hamster = Hamster.create(); + + hamster.get('hasBananas'); // false + hamster.set('numBananas', 0); + hamster.get('hasBananas'); // false + hamster.set('numBananas', 1); + hamster.get('hasBananas'); // true + hamster.set('numBananas', null); + hamster.get('hasBananas'); // false + ``` + + @method computed.bool + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which converts + to boolean the original value for property + */ + registerComputed('bool', function(dependentKey) { + return !!get(this, dependentKey); + }); + + /** + A computed property which matches the original value for the + dependent property against a given RegExp, returning `true` + if they values matches the RegExp and `false` if it does not. + + Example + + ```javascript + var User = Ember.Object.extend({ + hasValidEmail: Ember.computed.match('email', /^.+@.+\..+$/) + }); + + var user = User.create({loggedIn: false}); + + user.get('hasValidEmail'); // false + user.set('email', ''); + user.get('hasValidEmail'); // false + user.set('email', 'ember_hamster@example.com'); + user.get('hasValidEmail'); // true + ``` + + @method computed.match + @for Ember + @param {String} dependentKey + @param {RegExp} regexp + @return {Ember.ComputedProperty} computed property which match + the original value for property against a given RegExp + */ + registerComputed('match', function(dependentKey, regexp) { + var value = get(this, dependentKey); + return typeof value === 'string' ? regexp.test(value) : false; + }); + + /** + A computed property that returns true if the provided dependent property + is equal to the given value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + napTime: Ember.computed.equal('state', 'sleepy') + }); + + var hamster = Hamster.create(); + + hamster.get('napTime'); // false + hamster.set('state', 'sleepy'); + hamster.get('napTime'); // true + hamster.set('state', 'hungry'); + hamster.get('napTime'); // false + ``` + + @method computed.equal + @for Ember + @param {String} dependentKey + @param {String|Number|Object} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is equal to the given value. + */ + registerComputed('equal', function(dependentKey, value) { + return get(this, dependentKey) === value; + }); + + /** + A computed property that returns true if the provided dependent property + is greater than the provided value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + hasTooManyBananas: Ember.computed.gt('numBananas', 10) + }); + + var hamster = Hamster.create(); + + hamster.get('hasTooManyBananas'); // false + hamster.set('numBananas', 3); + hamster.get('hasTooManyBananas'); // false + hamster.set('numBananas', 11); + hamster.get('hasTooManyBananas'); // true + ``` + + @method computed.gt + @for Ember + @param {String} dependentKey + @param {Number} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is greater than given value. + */ + registerComputed('gt', function(dependentKey, value) { + return get(this, dependentKey) > value; + }); + + /** + A computed property that returns true if the provided dependent property + is greater than or equal to the provided value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + hasTooManyBananas: Ember.computed.gte('numBananas', 10) + }); + + var hamster = Hamster.create(); + + hamster.get('hasTooManyBananas'); // false + hamster.set('numBananas', 3); + hamster.get('hasTooManyBananas'); // false + hamster.set('numBananas', 10); + hamster.get('hasTooManyBananas'); // true + ``` + + @method computed.gte + @for Ember + @param {String} dependentKey + @param {Number} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is greater or equal then given value. + */ + registerComputed('gte', function(dependentKey, value) { + return get(this, dependentKey) >= value; + }); + + /** + A computed property that returns true if the provided dependent property + is less than the provided value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + needsMoreBananas: Ember.computed.lt('numBananas', 3) + }); + + var hamster = Hamster.create(); + + hamster.get('needsMoreBananas'); // true + hamster.set('numBananas', 3); + hamster.get('needsMoreBananas'); // false + hamster.set('numBananas', 2); + hamster.get('needsMoreBananas'); // true + ``` + + @method computed.lt + @for Ember + @param {String} dependentKey + @param {Number} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is less then given value. + */ + registerComputed('lt', function(dependentKey, value) { + return get(this, dependentKey) < value; + }); + + /** + A computed property that returns true if the provided dependent property + is less than or equal to the provided value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + needsMoreBananas: Ember.computed.lte('numBananas', 3) + }); + + var hamster = Hamster.create(); + + hamster.get('needsMoreBananas'); // true + hamster.set('numBananas', 5); + hamster.get('needsMoreBananas'); // false + hamster.set('numBananas', 3); + hamster.get('needsMoreBananas'); // true + ``` + + @method computed.lte + @for Ember + @param {String} dependentKey + @param {Number} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is less or equal than given value. + */ + registerComputed('lte', function(dependentKey, value) { + return get(this, dependentKey) <= value; + }); + + /** + A computed property that performs a logical `and` on the + original values for the provided dependent properties. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + readyForCamp: Ember.computed.and('hasTent', 'hasBackpack') + }); + + var hamster = Hamster.create(); + + hamster.get('readyForCamp'); // false + hamster.set('hasTent', true); + hamster.get('readyForCamp'); // false + hamster.set('hasBackpack', true); + hamster.get('readyForCamp'); // true + ``` + + @method computed.and + @for Ember + @param {String} dependentKey* + @return {Ember.ComputedProperty} computed property which performs + a logical `and` on the values of all the original values for properties. + */ + registerComputedWithProperties('and', function(properties) { + for (var key in properties) { + if (properties.hasOwnProperty(key) && !properties[key]) { + return false; + } + } + return true; + }); + + /** + A computed property which performs a logical `or` on the + original values for the provided dependent properties. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + readyForRain: Ember.computed.or('hasJacket', 'hasUmbrella') + }); + + var hamster = Hamster.create(); + + hamster.get('readyForRain'); // false + hamster.set('hasJacket', true); + hamster.get('readyForRain'); // true + ``` + + @method computed.or + @for Ember + @param {String} dependentKey* + @return {Ember.ComputedProperty} computed property which performs + a logical `or` on the values of all the original values for properties. + */ + registerComputedWithProperties('or', function(properties) { + for (var key in properties) { + if (properties.hasOwnProperty(key) && properties[key]) { + return true; + } + } + return false; + }); + + /** + A computed property that returns the first truthy value + from a list of dependent properties. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + hasClothes: Ember.computed.any('hat', 'shirt') + }); + + var hamster = Hamster.create(); + + hamster.get('hasClothes'); // null + hamster.set('shirt', 'Hawaiian Shirt'); + hamster.get('hasClothes'); // 'Hawaiian Shirt' + ``` + + @method computed.any + @for Ember + @param {String} dependentKey* + @return {Ember.ComputedProperty} computed property which returns + the first truthy value of given list of properties. + */ + registerComputedWithProperties('any', function(properties) { + for (var key in properties) { + if (properties.hasOwnProperty(key) && properties[key]) { + return properties[key]; + } + } + return null; + }); + + /** + A computed property that returns the array of values + for the provided dependent properties. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + clothes: Ember.computed.collect('hat', 'shirt') + }); + + var hamster = Hamster.create(); + + hamster.get('clothes'); // [null, null] + hamster.set('hat', 'Camp Hat'); + hamster.set('shirt', 'Camp Shirt'); + hamster.get('clothes'); // ['Camp Hat', 'Camp Shirt'] + ``` + + @method computed.collect + @for Ember + @param {String} dependentKey* + @return {Ember.ComputedProperty} computed property which maps + values of all passed in properties to an array. + */ + registerComputedWithProperties('collect', function(properties) { + var res = []; + for (var key in properties) { + if (properties.hasOwnProperty(key)) { + if (isNone(properties[key])) { + res.push(null); + } else { + res.push(properties[key]); + } + } + } + return res; + }); + + /** + Creates a new property that is an alias for another property + on an object. Calls to `get` or `set` this property behave as + though they were called on the original property. + + ```javascript + var Person = Ember.Object.extend({ + name: 'Alex Matchneer', + nomen: Ember.computed.alias('name') + }); + + var alex = Person.create(); + + alex.get('nomen'); // 'Alex Matchneer' + alex.get('name'); // 'Alex Matchneer' + + alex.set('nomen', '@machty'); + alex.get('name'); // '@machty' + ``` + + @method computed.alias + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which creates an + alias to the original value for property. + */ + computed.alias = alias; + + /** + Where `computed.alias` aliases `get` and `set`, and allows for bidirectional + data flow, `computed.oneWay` only provides an aliased `get`. The `set` will + not mutate the upstream property, rather causes the current property to + become the value set. This causes the downstream property to permanently + diverge from the upstream property. + + Example + + ```javascript + var User = Ember.Object.extend({ + firstName: null, + lastName: null, + nickName: Ember.computed.oneWay('firstName') + }); + + var teddy = User.create({ + firstName: 'Teddy', + lastName: 'Zeenny' + }); + + teddy.get('nickName'); // 'Teddy' + teddy.set('nickName', 'TeddyBear'); // 'TeddyBear' + teddy.get('firstName'); // 'Teddy' + ``` + + @method computed.oneWay + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which creates a + one way computed property to the original value for property. + */ + computed.oneWay = function(dependentKey) { + return alias(dependentKey).oneWay(); + }; + + /** + This is a more semantically meaningful alias of `computed.oneWay`, + whose name is somewhat ambiguous as to which direction the data flows. + + @method computed.reads + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which creates a + one way computed property to the original value for property. + */ + computed.reads = computed.oneWay; + + /** + Where `computed.oneWay` provides oneWay bindings, `computed.readOnly` provides + a readOnly one way binding. Very often when using `computed.oneWay` one does + not also want changes to propogate back up, as they will replace the value. + + This prevents the reverse flow, and also throws an exception when it occurs. + + Example + + ```javascript + var User = Ember.Object.extend({ + firstName: null, + lastName: null, + nickName: Ember.computed.readOnly('firstName') + }); + + var teddy = User.create({ + firstName: 'Teddy', + lastName: 'Zeenny' + }); + + teddy.get('nickName'); // 'Teddy' + teddy.set('nickName', 'TeddyBear'); // throws Exception + // throw new Ember.Error('Cannot Set: nickName on: ' );` + teddy.get('firstName'); // 'Teddy' + ``` + + @method computed.readOnly + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which creates a + one way computed property to the original value for property. + @since 1.5.0 + */ + computed.readOnly = function(dependentKey) { + return alias(dependentKey).readOnly(); + }; + /** + A computed property that acts like a standard getter and setter, + but returns the value at the provided `defaultPath` if the + property itself has not been set to a value + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + wishList: Ember.computed.defaultTo('favoriteFood') + }); + + var hamster = Hamster.create({ favoriteFood: 'Banana' }); + + hamster.get('wishList'); // 'Banana' + hamster.set('wishList', 'More Unit Tests'); + hamster.get('wishList'); // 'More Unit Tests' + hamster.get('favoriteFood'); // 'Banana' + ``` + + @method computed.defaultTo + @for Ember + @param {String} defaultPath + @return {Ember.ComputedProperty} computed property which acts like + a standard getter and setter, but defaults to the value from `defaultPath`. + @deprecated Use `Ember.computed.oneWay` or custom CP with default instead. + */ + // ES6TODO: computed should have its own export path so you can do import {defaultTo} from computed + computed.defaultTo = function(defaultPath) { + return computed(function(key, newValue, cachedValue) { + Ember.deprecate('Usage of Ember.computed.defaultTo is deprecated, use `Ember.computed.oneWay` instead.'); + + if (arguments.length === 1) { + return get(this, defaultPath); + } + return newValue != null ? newValue : get(this, defaultPath); + }); + }; + + /** + Creates a new property that is an alias for another property + on an object. Calls to `get` or `set` this property behave as + though they were called on the original property, but also + print a deprecation warning. + + @method computed.deprecatingAlias + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which creates an + alias with a deprecation to the original value for property. + @since 1.7.0 + */ + computed.deprecatingAlias = function(dependentKey) { + return computed(dependentKey, function(key, value) { + Ember.deprecate('Usage of `' + key + '` is deprecated, use `' + dependentKey + '` instead.'); + + if (arguments.length > 1) { + set(this, dependentKey, value); + return value; + } else { + return get(this, dependentKey); + } + }); + }; + }); +enifed("ember-metal/core", + ["exports"], + function(__exports__) { + "use strict"; + /*globals Ember:true,Em:true,ENV,EmberENV,MetamorphENV:true */ + + /** + @module ember + @submodule ember-metal + */ + + /** + All Ember methods and functions are defined inside of this namespace. You + generally should not add new properties to this namespace as it may be + overwritten by future versions of Ember. + + You can also use the shorthand `Em` instead of `Ember`. + + Ember-Runtime is a framework that provides core functions for Ember including + cross-platform functions, support for property observing and objects. Its + focus is on small size and performance. You can use this in place of or + along-side other cross-platform libraries such as jQuery. + + The core Runtime framework is based on the jQuery API with a number of + performance optimizations. + + @class Ember + @static + @version 1.8.0 + */ + + if ('undefined' === typeof Ember) { + // Create core object. Make it act like an instance of Ember.Namespace so that + // objects assigned to it are given a sane string representation. + Ember = {}; + } + + // Default imports, exports and lookup to the global object; + var imports = Ember.imports = Ember.imports || this; + var exports = Ember.exports = Ember.exports || this; + var lookup = Ember.lookup = Ember.lookup || this; + + // aliases needed to keep minifiers from removing the global context + exports.Em = exports.Ember = Ember; + + // Make sure these are set whether Ember was already defined or not + + Ember.isNamespace = true; + + Ember.toString = function() { return "Ember"; }; + + + /** + @property VERSION + @type String + @default '1.8.0' + @static + */ + Ember.VERSION = '1.8.0'; + + /** + Standard environmental variables. You can define these in a global `EmberENV` + variable before loading Ember to control various configuration settings. + + For backwards compatibility with earlier versions of Ember the global `ENV` + variable will be used if `EmberENV` is not defined. + + @property ENV + @type Hash + */ + + if (Ember.ENV) { + // do nothing if Ember.ENV is already setup + } else if ('undefined' !== typeof EmberENV) { + Ember.ENV = EmberENV; + } else if('undefined' !== typeof ENV) { + Ember.ENV = ENV; + } else { + Ember.ENV = {}; + } + + Ember.config = Ember.config || {}; + + // We disable the RANGE API by default for performance reasons + if ('undefined' === typeof Ember.ENV.DISABLE_RANGE_API) { + Ember.ENV.DISABLE_RANGE_API = true; + } + + if ("undefined" === typeof MetamorphENV) { + exports.MetamorphENV = {}; + } + + MetamorphENV.DISABLE_RANGE_API = Ember.ENV.DISABLE_RANGE_API; + + /** + Hash of enabled Canary features. Add to this before creating your application. + + You can also define `ENV.FEATURES` if you need to enable features flagged at runtime. + + @class FEATURES + @namespace Ember + @static + @since 1.1.0 + */ + + Ember.FEATURES = Ember.ENV.FEATURES || {}; + + /** + Test that a feature is enabled. Parsed by Ember's build tools to leave + experimental features out of beta/stable builds. + + You can define the following configuration options: + + * `ENV.ENABLE_ALL_FEATURES` - force all features to be enabled. + * `ENV.ENABLE_OPTIONAL_FEATURES` - enable any features that have not been explicitly + enabled/disabled. + + @method isEnabled + @param {String} feature + @return {Boolean} + @for Ember.FEATURES + @since 1.1.0 + */ + + Ember.FEATURES.isEnabled = function(feature) { + var featureValue = Ember.FEATURES[feature]; + + if (Ember.ENV.ENABLE_ALL_FEATURES) { + return true; + } else if (featureValue === true || featureValue === false || featureValue === undefined) { + return featureValue; + } else if (Ember.ENV.ENABLE_OPTIONAL_FEATURES) { + return true; + } else { + return false; + } + }; + + // .......................................................... + // BOOTSTRAP + // + + /** + Determines whether Ember should enhance some built-in object prototypes to + provide a more friendly API. If enabled, a few methods will be added to + `Function`, `String`, and `Array`. `Object.prototype` will not be enhanced, + which is the one that causes most trouble for people. + + In general we recommend leaving this option set to true since it rarely + conflicts with other code. If you need to turn it off however, you can + define an `ENV.EXTEND_PROTOTYPES` config to disable it. + + @property EXTEND_PROTOTYPES + @type Boolean + @default true + @for Ember + */ + Ember.EXTEND_PROTOTYPES = Ember.ENV.EXTEND_PROTOTYPES; + + if (typeof Ember.EXTEND_PROTOTYPES === 'undefined') { + Ember.EXTEND_PROTOTYPES = true; + } + + /** + Determines whether Ember logs a full stack trace during deprecation warnings + + @property LOG_STACKTRACE_ON_DEPRECATION + @type Boolean + @default true + */ + Ember.LOG_STACKTRACE_ON_DEPRECATION = (Ember.ENV.LOG_STACKTRACE_ON_DEPRECATION !== false); + + /** + Determines whether Ember should add ECMAScript 5 shims to older browsers. + + @property SHIM_ES5 + @type Boolean + @default Ember.EXTEND_PROTOTYPES + */ + Ember.SHIM_ES5 = (Ember.ENV.SHIM_ES5 === false) ? false : Ember.EXTEND_PROTOTYPES; + + /** + Determines whether Ember logs info about version of used libraries + + @property LOG_VERSION + @type Boolean + @default true + */ + Ember.LOG_VERSION = (Ember.ENV.LOG_VERSION === false) ? false : true; + + /** + Empty function. Useful for some operations. Always returns `this`. + + @method K + @private + @return {Object} + */ + var K = function() { return this; }; + var K = K; + __exports__.K = K;Ember.K = K; + //TODO: ES6 GLOBL TODO + + // Stub out the methods defined by the ember-debug package in case it's not loaded + + if ('undefined' === typeof Ember.assert) { Ember.assert = Ember.K; } + if ('undefined' === typeof Ember.warn) { Ember.warn = Ember.K; } + if ('undefined' === typeof Ember.debug) { Ember.debug = Ember.K; } + if ('undefined' === typeof Ember.runInDebug) { Ember.runInDebug = Ember.K; } + if ('undefined' === typeof Ember.deprecate) { Ember.deprecate = Ember.K; } + if ('undefined' === typeof Ember.deprecateFunc) { + Ember.deprecateFunc = function(_, func) { return func; }; + } + + __exports__["default"] = Ember; + }); +enifed("ember-metal/dependent_keys", + ["ember-metal/platform","ember-metal/watching","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var create = __dependency1__.create; + var watch = __dependency2__.watch; + var unwatch = __dependency2__.unwatch; + + /** + @module ember-metal + */ + + var o_create = create; + + // .......................................................... + // DEPENDENT KEYS + // + + // data structure: + // meta.deps = { + // 'depKey': { + // 'keyName': count, + // } + // } + + /* + This function returns a map of unique dependencies for a + given object and key. + */ + function keysForDep(depsMeta, depKey) { + var keys = depsMeta[depKey]; + if (!keys) { + // if there are no dependencies yet for a the given key + // create a new empty list of dependencies for the key + keys = depsMeta[depKey] = {}; + } else if (!depsMeta.hasOwnProperty(depKey)) { + // otherwise if the dependency list is inherited from + // a superclass, clone the hash + keys = depsMeta[depKey] = o_create(keys); + } + return keys; + } + + function metaForDeps(meta) { + return keysForDep(meta, 'deps'); + } + + function addDependentKeys(desc, obj, keyName, meta) { + // the descriptor has a list of dependent keys, so + // add all of its dependent keys. + var depKeys = desc._dependentKeys, depsMeta, idx, len, depKey, keys; + if (!depKeys) return; + + depsMeta = metaForDeps(meta); + + for(idx = 0, len = depKeys.length; idx < len; idx++) { + depKey = depKeys[idx]; + // Lookup keys meta for depKey + keys = keysForDep(depsMeta, depKey); + // Increment the number of times depKey depends on keyName. + keys[keyName] = (keys[keyName] || 0) + 1; + // Watch the depKey + watch(obj, depKey, meta); + } + } + + __exports__.addDependentKeys = addDependentKeys;function removeDependentKeys(desc, obj, keyName, meta) { + // the descriptor has a list of dependent keys, so + // remove all of its dependent keys. + var depKeys = desc._dependentKeys, depsMeta, idx, len, depKey, keys; + if (!depKeys) return; + + depsMeta = metaForDeps(meta); + + for(idx = 0, len = depKeys.length; idx < len; idx++) { + depKey = depKeys[idx]; + // Lookup keys meta for depKey + keys = keysForDep(depsMeta, depKey); + // Decrement the number of times depKey depends on keyName. + keys[keyName] = (keys[keyName] || 0) - 1; + // Unwatch the depKey + unwatch(obj, depKey, meta); + } + } + + __exports__.removeDependentKeys = removeDependentKeys; + }); +enifed("ember-metal/deprecate_property", + ["ember-metal/core","ember-metal/platform","ember-metal/properties","ember-metal/property_get","ember-metal/property_set","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + /** + @module ember-metal + */ + + var Ember = __dependency1__["default"]; + var hasPropertyAccessors = __dependency2__.hasPropertyAccessors; + var defineProperty = __dependency3__.defineProperty; + var get = __dependency4__.get; + var set = __dependency5__.set; + + + /** + Used internally to allow changing properties in a backwards compatible way, and print a helpful + deprecation warning. + + @method deprecateProperty + @param {Object} object The object to add the deprecated property to. + @param {String} deprecatedKey The property to add (and print deprecation warnings upon accessing). + @param {String} newKey The property that will be aliased. + @private + @since 1.7.0 + */ + + function deprecateProperty(object, deprecatedKey, newKey) { + function deprecate() { + Ember.deprecate('Usage of `' + deprecatedKey + '` is deprecated, use `' + newKey + '` instead.'); + } + + if (hasPropertyAccessors) { + defineProperty(object, deprecatedKey, { + configurable: true, + enumerable: false, + set: function(value) { deprecate(); set(this, newKey, value); }, + get: function() { deprecate(); return get(this, newKey); } + }); + } + } + + __exports__.deprecateProperty = deprecateProperty; + }); +enifed("ember-metal/dictionary", + ["ember-metal/platform","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var create = __dependency1__.create; + + // the delete is meant to hint at runtimes that this object should remain in + // dictionary mode. This is clearly a runtime specific hack, but currently it + // appears worthwile in some usecases. Please note, these deletes do increase + // the cost of creation dramatically over a plain Object.create. And as this + // only makes sense for long-lived dictionaries that aren't instantiated often. + __exports__["default"] = function makeDictionary(parent) { + var dict = create(parent); + dict['_dict'] = null; + delete dict['_dict']; + return dict; + } + }); +enifed("ember-metal/enumerable_utils", + ["ember-metal/array","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var _filter = __dependency1__.filter; + var a_forEach = __dependency1__.forEach; + var _indexOf = __dependency1__.indexOf; + var _map = __dependency1__.map; + + var splice = Array.prototype.splice; + + /** + * Defines some convenience methods for working with Enumerables. + * `Ember.EnumerableUtils` uses `Ember.ArrayPolyfills` when necessary. + * + * @class EnumerableUtils + * @namespace Ember + * @static + * */ + + /** + * Calls the map function on the passed object with a specified callback. This + * uses `Ember.ArrayPolyfill`'s-map method when necessary. + * + * @method map + * @param {Object} obj The object that should be mapped + * @param {Function} callback The callback to execute + * @param {Object} thisArg Value to use as this when executing *callback* + * + * @return {Array} An array of mapped values. + */ + function map(obj, callback, thisArg) { + return obj.map ? obj.map(callback, thisArg) : _map.call(obj, callback, thisArg); + } + + __exports__.map = map;/** + * Calls the forEach function on the passed object with a specified callback. This + * uses `Ember.ArrayPolyfill`'s-forEach method when necessary. + * + * @method forEach + * @param {Object} obj The object to call forEach on + * @param {Function} callback The callback to execute + * @param {Object} thisArg Value to use as this when executing *callback* + * + */ + function forEach(obj, callback, thisArg) { + return obj.forEach ? obj.forEach(callback, thisArg) : a_forEach.call(obj, callback, thisArg); + } + + __exports__.forEach = forEach;/** + * Calls the filter function on the passed object with a specified callback. This + * uses `Ember.ArrayPolyfill`'s-filter method when necessary. + * + * @method filter + * @param {Object} obj The object to call filter on + * @param {Function} callback The callback to execute + * @param {Object} thisArg Value to use as this when executing *callback* + * + * @return {Array} An array containing the filtered values + * @since 1.4.0 + */ + function filter(obj, callback, thisArg) { + return obj.filter ? obj.filter(callback, thisArg) : _filter.call(obj, callback, thisArg); + } + + __exports__.filter = filter;/** + * Calls the indexOf function on the passed object with a specified callback. This + * uses `Ember.ArrayPolyfill`'s-indexOf method when necessary. + * + * @method indexOf + * @param {Object} obj The object to call indexOn on + * @param {Function} callback The callback to execute + * @param {Object} index The index to start searching from + * + */ + function indexOf(obj, element, index) { + return obj.indexOf ? obj.indexOf(element, index) : _indexOf.call(obj, element, index); + } + + __exports__.indexOf = indexOf;/** + * Returns an array of indexes of the first occurrences of the passed elements + * on the passed object. + * + * ```javascript + * var array = [1, 2, 3, 4, 5]; + * Ember.EnumerableUtils.indexesOf(array, [2, 5]); // [1, 4] + * + * var fubar = "Fubarr"; + * Ember.EnumerableUtils.indexesOf(fubar, ['b', 'r']); // [2, 4] + * ``` + * + * @method indexesOf + * @param {Object} obj The object to check for element indexes + * @param {Array} elements The elements to search for on *obj* + * + * @return {Array} An array of indexes. + * + */ + function indexesOf(obj, elements) { + return elements === undefined ? [] : map(elements, function(item) { + return indexOf(obj, item); + }); + } + + __exports__.indexesOf = indexesOf;/** + * Adds an object to an array. If the array already includes the object this + * method has no effect. + * + * @method addObject + * @param {Array} array The array the passed item should be added to + * @param {Object} item The item to add to the passed array + * + * @return 'undefined' + */ + function addObject(array, item) { + var index = indexOf(array, item); + if (index === -1) { array.push(item); } + } + + __exports__.addObject = addObject;/** + * Removes an object from an array. If the array does not contain the passed + * object this method has no effect. + * + * @method removeObject + * @param {Array} array The array to remove the item from. + * @param {Object} item The item to remove from the passed array. + * + * @return 'undefined' + */ + function removeObject(array, item) { + var index = indexOf(array, item); + if (index !== -1) { array.splice(index, 1); } + } + + __exports__.removeObject = removeObject;function _replace(array, idx, amt, objects) { + var args = [].concat(objects); + var ret = []; + // https://code.google.com/p/chromium/issues/detail?id=56588 + var size = 60000; + var start = idx; + var ends = amt; + var count, chunk; + + while (args.length) { + count = ends > size ? size : ends; + if (count <= 0) { count = 0; } + + chunk = args.splice(0, size); + chunk = [start, count].concat(chunk); + + start += size; + ends -= count; + + ret = ret.concat(splice.apply(array, chunk)); + } + return ret; + } + + __exports__._replace = _replace;/** + * Replaces objects in an array with the passed objects. + * + * ```javascript + * var array = [1,2,3]; + * Ember.EnumerableUtils.replace(array, 1, 2, [4, 5]); // [1, 4, 5] + * + * var array = [1,2,3]; + * Ember.EnumerableUtils.replace(array, 1, 1, [4, 5]); // [1, 4, 5, 3] + * + * var array = [1,2,3]; + * Ember.EnumerableUtils.replace(array, 10, 1, [4, 5]); // [1, 2, 3, 4, 5] + * ``` + * + * @method replace + * @param {Array} array The array the objects should be inserted into. + * @param {Number} idx Starting index in the array to replace. If *idx* >= + * length, then append to the end of the array. + * @param {Number} amt Number of elements that should be removed from the array, + * starting at *idx* + * @param {Array} objects An array of zero or more objects that should be + * inserted into the array at *idx* + * + * @return {Array} The modified array. + */ + function replace(array, idx, amt, objects) { + if (array.replace) { + return array.replace(idx, amt, objects); + } else { + return _replace(array, idx, amt, objects); + } + } + + __exports__.replace = replace;/** + * Calculates the intersection of two arrays. This method returns a new array + * filled with the records that the two passed arrays share with each other. + * If there is no intersection, an empty array will be returned. + * + * ```javascript + * var array1 = [1, 2, 3, 4, 5]; + * var array2 = [1, 3, 5, 6, 7]; + * + * Ember.EnumerableUtils.intersection(array1, array2); // [1, 3, 5] + * + * var array1 = [1, 2, 3]; + * var array2 = [4, 5, 6]; + * + * Ember.EnumerableUtils.intersection(array1, array2); // [] + * ``` + * + * @method intersection + * @param {Array} array1 The first array + * @param {Array} array2 The second array + * + * @return {Array} The intersection of the two passed arrays. + */ + function intersection(array1, array2) { + var result = []; + forEach(array1, function(element) { + if (indexOf(array2, element) >= 0) { + result.push(element); + } + }); + + return result; + } + + __exports__.intersection = intersection;// TODO: this only exists to maintain the existing api, as we move forward it + // should only be part of the "global build" via some shim + __exports__["default"] = { + _replace: _replace, + addObject: addObject, + filter: filter, + forEach: forEach, + indexOf: indexOf, + indexesOf: indexesOf, + intersection: intersection, + map: map, + removeObject: removeObject, + replace: replace + }; + }); +enifed("ember-metal/error", + ["ember-metal/platform","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var create = __dependency1__.create; + + var errorProps = [ + 'description', + 'fileName', + 'lineNumber', + 'message', + 'name', + 'number', + 'stack' + ]; + + /** + A subclass of the JavaScript Error object for use in Ember. + + @class Error + @namespace Ember + @extends Error + @constructor + */ + function EmberError() { + var tmp = Error.apply(this, arguments); + + // Adds a `stack` property to the given error object that will yield the + // stack trace at the time captureStackTrace was called. + // When collecting the stack trace all frames above the topmost call + // to this function, including that call, will be left out of the + // stack trace. + // This is useful because we can hide Ember implementation details + // that are not very helpful for the user. + if (Error.captureStackTrace) { + Error.captureStackTrace(this, Ember.Error); + } + // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. + for (var idx = 0; idx < errorProps.length; idx++) { + this[errorProps[idx]] = tmp[errorProps[idx]]; + } + } + + EmberError.prototype = create(Error.prototype); + + __exports__["default"] = EmberError; + }); +enifed("ember-metal/events", + ["ember-metal/core","ember-metal/utils","ember-metal/platform","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + /** + @module ember-metal + */ + var Ember = __dependency1__["default"]; + var meta = __dependency2__.meta; + var tryFinally = __dependency2__.tryFinally; + var apply = __dependency2__.apply; + var applyStr = __dependency2__.applyStr; + var create = __dependency3__.create; + + var a_slice = [].slice; + var metaFor = meta; + + /* listener flags */ + var ONCE = 1; + var SUSPENDED = 2; + + + /* + The event system uses a series of nested hashes to store listeners on an + object. When a listener is registered, or when an event arrives, these + hashes are consulted to determine which target and action pair to invoke. + + The hashes are stored in the object's meta hash, and look like this: + + // Object's meta hash + { + listeners: { // variable name: `listenerSet` + "foo:changed": [ // variable name: `actions` + target, method, flags + ] + } + } + + */ + + function indexOf(array, target, method) { + var index = -1; + // hashes are added to the end of the event array + // so it makes sense to start searching at the end + // of the array and search in reverse + for (var i = array.length - 3 ; i >=0; i -= 3) { + if (target === array[i] && method === array[i + 1]) { + index = i; break; + } + } + return index; + } + + function actionsFor(obj, eventName) { + var meta = metaFor(obj, true); + var actions; + + if (!meta.listeners) { meta.listeners = {}; } + + if (!meta.hasOwnProperty('listeners')) { + // setup inherited copy of the listeners object + meta.listeners = create(meta.listeners); + } + + actions = meta.listeners[eventName]; + + // if there are actions, but the eventName doesn't exist in our listeners, then copy them from the prototype + if (actions && !meta.listeners.hasOwnProperty(eventName)) { + actions = meta.listeners[eventName] = meta.listeners[eventName].slice(); + } else if (!actions) { + actions = meta.listeners[eventName] = []; + } + + return actions; + } + + function listenersUnion(obj, eventName, otherActions) { + var meta = obj['__ember_meta__']; + var actions = meta && meta.listeners && meta.listeners[eventName]; + + if (!actions) { return; } + for (var i = actions.length - 3; i >= 0; i -= 3) { + var target = actions[i]; + var method = actions[i+1]; + var flags = actions[i+2]; + var actionIndex = indexOf(otherActions, target, method); + + if (actionIndex === -1) { + otherActions.push(target, method, flags); + } + } + } + + __exports__.listenersUnion = listenersUnion;function listenersDiff(obj, eventName, otherActions) { + var meta = obj['__ember_meta__']; + var actions = meta && meta.listeners && meta.listeners[eventName]; + var diffActions = []; + + if (!actions) { return; } + for (var i = actions.length - 3; i >= 0; i -= 3) { + var target = actions[i]; + var method = actions[i+1]; + var flags = actions[i+2]; + var actionIndex = indexOf(otherActions, target, method); + + if (actionIndex !== -1) { continue; } + + otherActions.push(target, method, flags); + diffActions.push(target, method, flags); + } + + return diffActions; + } + + __exports__.listenersDiff = listenersDiff;/** + Add an event listener + + @method addListener + @for Ember + @param obj + @param {String} eventName + @param {Object|Function} targetOrMethod A target object or a function + @param {Function|String} method A function or the name of a function to be called on `target` + @param {Boolean} once A flag whether a function should only be called once + */ + function addListener(obj, eventName, target, method, once) { + Ember.assert("You must pass at least an object and event name to Ember.addListener", !!obj && !!eventName); + + if (!method && 'function' === typeof target) { + method = target; + target = null; + } + + var actions = actionsFor(obj, eventName); + var actionIndex = indexOf(actions, target, method); + var flags = 0; + + if (once) flags |= ONCE; + + if (actionIndex !== -1) { return; } + + actions.push(target, method, flags); + + if ('function' === typeof obj.didAddListener) { + obj.didAddListener(eventName, target, method); + } + } + + __exports__.addListener = addListener;/** + Remove an event listener + + Arguments should match those passed to `Ember.addListener`. + + @method removeListener + @for Ember + @param obj + @param {String} eventName + @param {Object|Function} targetOrMethod A target object or a function + @param {Function|String} method A function or the name of a function to be called on `target` + */ + function removeListener(obj, eventName, target, method) { + Ember.assert("You must pass at least an object and event name to Ember.removeListener", !!obj && !!eventName); + + if (!method && 'function' === typeof target) { + method = target; + target = null; + } + + function _removeListener(target, method) { + var actions = actionsFor(obj, eventName); + var actionIndex = indexOf(actions, target, method); + + // action doesn't exist, give up silently + if (actionIndex === -1) { return; } + + actions.splice(actionIndex, 3); + + if ('function' === typeof obj.didRemoveListener) { + obj.didRemoveListener(eventName, target, method); + } + } + + if (method) { + _removeListener(target, method); + } else { + var meta = obj['__ember_meta__']; + var actions = meta && meta.listeners && meta.listeners[eventName]; + + if (!actions) { return; } + for (var i = actions.length - 3; i >= 0; i -= 3) { + _removeListener(actions[i], actions[i+1]); + } + } + } + + /** + Suspend listener during callback. + + This should only be used by the target of the event listener + when it is taking an action that would cause the event, e.g. + an object might suspend its property change listener while it is + setting that property. + + @method suspendListener + @for Ember + + @private + @param obj + @param {String} eventName + @param {Object|Function} targetOrMethod A target object or a function + @param {Function|String} method A function or the name of a function to be called on `target` + @param {Function} callback + */ + function suspendListener(obj, eventName, target, method, callback) { + if (!method && 'function' === typeof target) { + method = target; + target = null; + } + + var actions = actionsFor(obj, eventName); + var actionIndex = indexOf(actions, target, method); + + if (actionIndex !== -1) { + actions[actionIndex+2] |= SUSPENDED; // mark the action as suspended + } + + function tryable() { return callback.call(target); } + function finalizer() { if (actionIndex !== -1) { actions[actionIndex+2] &= ~SUSPENDED; } } + + return tryFinally(tryable, finalizer); + } + + __exports__.suspendListener = suspendListener;/** + Suspends multiple listeners during a callback. + + @method suspendListeners + @for Ember + + @private + @param obj + @param {Array} eventName Array of event names + @param {Object|Function} targetOrMethod A target object or a function + @param {Function|String} method A function or the name of a function to be called on `target` + @param {Function} callback + */ + function suspendListeners(obj, eventNames, target, method, callback) { + if (!method && 'function' === typeof target) { + method = target; + target = null; + } + + var suspendedActions = []; + var actionsList = []; + var eventName, actions, i, l; + + for (i=0, l=eventNames.length; i= 0; i -= 3) { // looping in reverse for once listeners + var target = actions[i], method = actions[i+1], flags = actions[i+2]; + if (!method) { continue; } + if (flags & SUSPENDED) { continue; } + if (flags & ONCE) { removeListener(obj, eventName, target, method); } + if (!target) { target = obj; } + if ('string' === typeof method) { + if (params) { + applyStr(target, method, params); + } else { + target[method](); + } + } else { + if (params) { + apply(target, method, params); + } else { + method.call(target); + } + } + } + return true; + } + + __exports__.sendEvent = sendEvent;/** + @private + @method hasListeners + @for Ember + @param obj + @param {String} eventName + */ + function hasListeners(obj, eventName) { + var meta = obj['__ember_meta__']; + var actions = meta && meta.listeners && meta.listeners[eventName]; + + return !!(actions && actions.length); + } + + __exports__.hasListeners = hasListeners;/** + @private + @method listenersFor + @for Ember + @param obj + @param {String} eventName + */ + function listenersFor(obj, eventName) { + var ret = []; + var meta = obj['__ember_meta__']; + var actions = meta && meta.listeners && meta.listeners[eventName]; + + if (!actions) { return ret; } + + for (var i = 0, l = actions.length; i < l; i += 3) { + var target = actions[i]; + var method = actions[i+1]; + ret.push([target, method]); + } + + return ret; + } + + __exports__.listenersFor = listenersFor;/** + Define a property as a function that should be executed when + a specified event or events are triggered. + + + ``` javascript + var Job = Ember.Object.extend({ + logCompleted: Ember.on('completed', function() { + console.log('Job completed!'); + }) + }); + + var job = Job.create(); + + Ember.sendEvent(job, 'completed'); // Logs 'Job completed!' + ``` + + @method on + @for Ember + @param {String} eventNames* + @param {Function} func + @return func + */ + function on(){ + var func = a_slice.call(arguments, -1)[0]; + var events = a_slice.call(arguments, 0, -1); + func.__ember_listens__ = events; + return func; + } + + __exports__.on = on;__exports__.removeListener = removeListener; + }); +enifed("ember-metal/expand_properties", + ["ember-metal/core","ember-metal/error","ember-metal/enumerable_utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var EmberError = __dependency2__["default"]; + var forEach = __dependency3__.forEach; + + /** + @module ember-metal + */ + + var BRACE_EXPANSION = /^((?:[^\.]*\.)*)\{(.*)\}$/; + var SPLIT_REGEX = /\{|\}/; + + /** + Expands `pattern`, invoking `callback` for each expansion. + + The only pattern supported is brace-expansion, anything else will be passed + once to `callback` directly. + + Example + + ```js + function echo(arg){ console.log(arg); } + + Ember.expandProperties('foo.bar', echo); //=> 'foo.bar' + Ember.expandProperties('{foo,bar}', echo); //=> 'foo', 'bar' + Ember.expandProperties('foo.{bar,baz}', echo); //=> 'foo.bar', 'foo.baz' + Ember.expandProperties('{foo,bar}.baz', echo); //=> '{foo,bar}.baz' + Ember.expandProperties('foo.{bar,baz}.@each', echo) //=> 'foo.bar.@each', 'foo.baz.@each' + Ember.expandProperties('{foo,bar}.{spam,eggs}', echo) //=> 'foo.spam', 'foo.eggs', 'bar.spam', 'bar.eggs' + Ember.expandProperties('{foo}.bar.{baz}') //=> 'foo.bar.baz' + ``` + + @method + @private + @param {String} pattern The property pattern to expand. + @param {Function} callback The callback to invoke. It is invoked once per + expansion, and is passed the expansion. + */ + __exports__["default"] = function expandProperties(pattern, callback) { + if (pattern.indexOf(' ') > -1) { + throw new EmberError('Brace expanded properties cannot contain spaces, ' + + 'e.g. `user.{firstName, lastName}` should be `user.{firstName,lastName}`'); + } + + + return newExpandProperties(pattern, callback); + } + + function oldExpandProperties(pattern, callback) { + var match, prefix, list; + + if (match = BRACE_EXPANSION.exec(pattern)) { + prefix = match[1]; + list = match[2]; + + forEach(list.split(','), function (suffix) { + callback(prefix + suffix); + }); + } else { + callback(pattern); + } + } + + function newExpandProperties(pattern, callback) { + if ('string' === Ember.typeOf(pattern)) { + var parts = pattern.split(SPLIT_REGEX); + var properties = [parts]; + + forEach(parts, function(part, index) { + if (part.indexOf(',') >= 0) { + properties = duplicateAndReplace(properties, part.split(','), index); + } + }); + + forEach(properties, function(property) { + callback(property.join('')); + }); + } else { + callback(pattern); + } + } + + function duplicateAndReplace(properties, currentParts, index) { + var all = []; + + forEach(properties, function(property) { + forEach(currentParts, function(part) { + var current = property.slice(0); + current[index] = part; + all.push(current); + }); + }); + + return all; + } + }); +enifed("ember-metal/get_properties", + ["ember-metal/property_get","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var typeOf = __dependency2__.typeOf; + + /** + To get multiple properties at once, call `Ember.getProperties` + with an object followed by a list of strings or an array: + + ```javascript + Ember.getProperties(record, 'firstName', 'lastName', 'zipCode'); + // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } + ``` + + is equivalent to: + + ```javascript + Ember.getProperties(record, ['firstName', 'lastName', 'zipCode']); + // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } + ``` + + @method getProperties + @param obj + @param {String...|Array} list of keys to get + @return {Hash} + */ + __exports__["default"] = function getProperties(obj) { + var ret = {}; + var propertyNames = arguments; + var i = 1; + + if (arguments.length === 2 && typeOf(arguments[1]) === 'array') { + i = 0; + propertyNames = arguments[1]; + } + for(var len = propertyNames.length; i < len; i++) { + ret[propertyNames[i]] = get(obj, propertyNames[i]); + } + return ret; + } + }); +enifed("ember-metal/instrumentation", + ["ember-metal/core","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var tryCatchFinally = __dependency2__.tryCatchFinally; + + /** + The purpose of the Ember Instrumentation module is + to provide efficient, general-purpose instrumentation + for Ember. + + Subscribe to a listener by using `Ember.subscribe`: + + ```javascript + Ember.subscribe("render", { + before: function(name, timestamp, payload) { + + }, + + after: function(name, timestamp, payload) { + + } + }); + ``` + + If you return a value from the `before` callback, that same + value will be passed as a fourth parameter to the `after` + callback. + + Instrument a block of code by using `Ember.instrument`: + + ```javascript + Ember.instrument("render.handlebars", payload, function() { + // rendering logic + }, binding); + ``` + + Event names passed to `Ember.instrument` are namespaced + by periods, from more general to more specific. Subscribers + can listen for events by whatever level of granularity they + are interested in. + + In the above example, the event is `render.handlebars`, + and the subscriber listened for all events beginning with + `render`. It would receive callbacks for events named + `render`, `render.handlebars`, `render.container`, or + even `render.handlebars.layout`. + + @class Instrumentation + @namespace Ember + @static + */ + var subscribers = []; + __exports__.subscribers = subscribers;var cache = {}; + + var populateListeners = function(name) { + var listeners = []; + var subscriber; + + for (var i=0, l=subscribers.length; i -1) { + list.splice(index, 1); + } + this.size = list.length; + return true; + } else { + return false; + } + }, + + /** + @method isEmpty + @return {Boolean} + */ + isEmpty: function() { + return this.size === 0; + }, + + /** + @method has + @param obj + @return {Boolean} + */ + has: function(obj) { + if (this.size === 0) { return false; } + + var guid = guidFor(obj); + var presenceSet = this.presenceSet; + + return presenceSet[guid] === true; + }, + + /** + @method forEach + @param {Function} fn + @param self + */ + forEach: function(fn /*, thisArg*/) { + if (typeof fn !== 'function') { + missingFunction(fn); + } + + if (this.size === 0) { return; } + + var list = this.list; + var length = arguments.length; + var i; + + if (length === 2) { + for (i = 0; i < list.length; i++) { + fn.call(arguments[1], list[i]); + } + } else { + for (i = 0; i < list.length; i++) { + fn(list[i]); + } + } + }, + + /** + @method toArray + @return {Array} + */ + toArray: function() { + return this.list.slice(); + }, + + /** + @method copy + @return {Ember.OrderedSet} + */ + copy: function() { + var Constructor = this.constructor; + var set = new Constructor(); + + set._silenceRemoveDeprecation = this._silenceRemoveDeprecation; + set.presenceSet = copyNull(this.presenceSet); + set.list = this.toArray(); + set.size = this.size; + + return set; + } + }; + + deprecateProperty(OrderedSet.prototype, 'length', 'size'); + + /** + A Map stores values indexed by keys. Unlike JavaScript's + default Objects, the keys of a Map can be any JavaScript + object. + + Internally, a Map has two data structures: + + 1. `keys`: an OrderedSet of all of the existing keys + 2. `values`: a JavaScript Object indexed by the `Ember.guidFor(key)` + + When a key/value pair is added for the first time, we + add the key to the `keys` OrderedSet, and create or + replace an entry in `values`. When an entry is deleted, + we delete its entry in `keys` and `values`. + + @class Map + @namespace Ember + @private + @constructor + */ + function Map() { + if (this instanceof this.constructor) { + this.keys = OrderedSet.create(); + this.keys._silenceRemoveDeprecation = true; + this.values = create(null); + this.size = 0; + } else { + missingNew("OrderedSet"); + } + } + + Ember.Map = Map; + + /** + @method create + @static + */ + Map.create = function() { + var Constructor = this; + return new Constructor(); + }; + + Map.prototype = { + constructor: Map, + + /** + This property will change as the number of objects in the map changes. + + @property size + @type number + @default 0 + */ + size: 0, + + /** + Retrieve the value associated with a given key. + + @method get + @param {*} key + @return {*} the value associated with the key, or `undefined` + */ + get: function(key) { + if (this.size === 0) { return; } + + var values = this.values; + var guid = guidFor(key); + + return values[guid]; + }, + + /** + Adds a value to the map. If a value for the given key has already been + provided, the new value will replace the old value. + + @method set + @param {*} key + @param {*} value + @return {Ember.Map} + */ + set: function(key, value) { + var keys = this.keys; + var values = this.values; + var guid = guidFor(key); + + // ensure we don't store -0 + var k = key === -0 ? 0 : key; + + keys.add(k, guid); + + values[guid] = value; + + this.size = keys.size; + + return this; + }, + + /** + @deprecated see delete + Removes a value from the map for an associated key. + + @method remove + @param {*} key + @return {Boolean} true if an item was removed, false otherwise + */ + remove: function(key) { + Ember.deprecate('Calling `Map.prototype.remove` has been deprecated, please use `Map.prototype.delete` instead.'); + + return this["delete"](key); + }, + + /** + Removes a value from the map for an associated key. + + @method delete + @param {*} key + @return {Boolean} true if an item was removed, false otherwise + */ + "delete": function(key) { + if (this.size === 0) { return false; } + // don't use ES6 "delete" because it will be annoying + // to use in browsers that are not ES6 friendly; + var keys = this.keys; + var values = this.values; + var guid = guidFor(key); + + if (keys["delete"](key, guid)) { + delete values[guid]; + this.size = keys.size; + return true; + } else { + return false; + } + }, + + /** + Check whether a key is present. + + @method has + @param {*} key + @return {Boolean} true if the item was present, false otherwise + */ + has: function(key) { + return this.keys.has(key); + }, + + /** + Iterate over all the keys and values. Calls the function once + for each key, passing in the key and value, in that order. + + The keys are guaranteed to be iterated over in insertion order. + + @method forEach + @param {Function} callback + @param {*} self if passed, the `this` value inside the + callback. By default, `this` is the map. + */ + forEach: function(callback /*, thisArg*/) { + if (typeof callback !== 'function') { + missingFunction(callback); + } + + if (this.size === 0) { return; } + + var length = arguments.length; + var map = this; + var cb, thisArg; + + if (length === 2) { + thisArg = arguments[1]; + cb = function(key) { + callback.call(thisArg, map.get(key), key); + }; + } else { + cb = function(key) { + callback(map.get(key), key); + }; + } + + this.keys.forEach(cb); + }, + + /** + @method clear + */ + clear: function() { + this.keys.clear(); + this.values = create(null); + this.size = 0; + }, + + /** + @method copy + @return {Ember.Map} + */ + copy: function() { + return copyMap(this, new Map()); + } + }; + + deprecateProperty(Map.prototype, 'length', 'size'); + + /** + @class MapWithDefault + @namespace Ember + @extends Ember.Map + @private + @constructor + @param [options] + @param {*} [options.defaultValue] + */ + function MapWithDefault(options) { + this._super$constructor(); + this.defaultValue = options.defaultValue; + } + + /** + @method create + @static + @param [options] + @param {*} [options.defaultValue] + @return {Ember.MapWithDefault|Ember.Map} If options are passed, returns + `Ember.MapWithDefault` otherwise returns `Ember.Map` + */ + MapWithDefault.create = function(options) { + if (options) { + return new MapWithDefault(options); + } else { + return new Map(); + } + }; + + MapWithDefault.prototype = create(Map.prototype); + MapWithDefault.prototype.constructor = MapWithDefault; + MapWithDefault.prototype._super$constructor = Map; + MapWithDefault.prototype._super$get = Map.prototype.get; + + /** + Retrieve the value associated with a given key. + + @method get + @param {*} key + @return {*} the value associated with the key, or the default value + */ + MapWithDefault.prototype.get = function(key) { + var hasValue = this.has(key); + + if (hasValue) { + return this._super$get(key); + } else { + var defaultValue = this.defaultValue(key); + this.set(key, defaultValue); + return defaultValue; + } + }; + + /** + @method copy + @return {Ember.MapWithDefault} + */ + MapWithDefault.prototype.copy = function() { + var Constructor = this.constructor; + return copyMap(this, new Constructor({ + defaultValue: this.defaultValue + })); + }; + + __exports__["default"] = Map; + + __exports__.OrderedSet = OrderedSet; + __exports__.Map = Map; + __exports__.MapWithDefault = MapWithDefault; + }); +enifed("ember-metal/merge", + ["ember-metal/keys","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var keys = __dependency1__["default"]; + + /** + Merge the contents of two objects together into the first object. + + ```javascript + Ember.merge({first: 'Tom'}, {last: 'Dale'}); // {first: 'Tom', last: 'Dale'} + var a = {first: 'Yehuda'}, b = {last: 'Katz'}; + Ember.merge(a, b); // a == {first: 'Yehuda', last: 'Katz'}, b == {last: 'Katz'} + ``` + + @method merge + @for Ember + @param {Object} original The object to merge into + @param {Object} updates The object to copy properties from + @return {Object} + */ + __exports__["default"] = function merge(original, updates) { + if (!updates || typeof updates !== 'object') { + return original; + } + + var props = keys(updates); + var prop; + var length = props.length; + + for (var i = 0; i < length; i++) { + prop = props[i]; + original[prop] = updates[prop]; + } + + return original; + } + }); +enifed("ember-metal/mixin", + ["ember-metal/core","ember-metal/merge","ember-metal/array","ember-metal/platform","ember-metal/utils","ember-metal/expand_properties","ember-metal/properties","ember-metal/computed","ember-metal/binding","ember-metal/observer","ember-metal/events","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-metal + */ + + var Ember = __dependency1__["default"]; + // warn, assert, wrap, et; + var merge = __dependency2__["default"]; + var map = __dependency3__.map; + var indexOf = __dependency3__.indexOf; + var forEach = __dependency3__.forEach; + var create = __dependency4__.create; + var guidFor = __dependency5__.guidFor; + var meta = __dependency5__.meta; + var wrap = __dependency5__.wrap; + var makeArray = __dependency5__.makeArray; + var apply = __dependency5__.apply; + var isArray = __dependency5__.isArray; + var expandProperties = __dependency6__["default"]; + var Descriptor = __dependency7__.Descriptor; + var defineProperty = __dependency7__.defineProperty; + var ComputedProperty = __dependency8__.ComputedProperty; + var Binding = __dependency9__.Binding; + var addObserver = __dependency10__.addObserver; + var removeObserver = __dependency10__.removeObserver; + var addBeforeObserver = __dependency10__.addBeforeObserver; + var removeBeforeObserver = __dependency10__.removeBeforeObserver; + var addListener = __dependency11__.addListener; + var removeListener = __dependency11__.removeListener; + + var REQUIRED; + var a_map = map; + var a_indexOf = indexOf; + var a_forEach = forEach; + var a_slice = [].slice; + var o_create = create; + var metaFor = meta; + + function superFunction(){ + var func = this.__nextSuper; + var ret; + if (func) { + var args = new Array(arguments.length); + for (var i = 0, l = args.length; i < l; i++) { + args[i] = arguments[i]; + } + this.__nextSuper = null; + ret = apply(this, func, args); + this.__nextSuper = func; + } + return ret; + } + + function mixinsMeta(obj) { + var m = metaFor(obj, true); + var ret = m.mixins; + if (!ret) { + ret = m.mixins = {}; + } else if (!m.hasOwnProperty('mixins')) { + ret = m.mixins = o_create(ret); + } + return ret; + } + + function initMixin(mixin, args) { + if (args && args.length > 0) { + mixin.mixins = a_map.call(args, function(x) { + if (x instanceof Mixin) { return x; } + + // Note: Manually setup a primitive mixin here. This is the only + // way to actually get a primitive mixin. This way normal creation + // of mixins will give you combined mixins... + var mixin = new Mixin(); + mixin.properties = x; + return mixin; + }); + } + return mixin; + } + + function isMethod(obj) { + return 'function' === typeof obj && + obj.isMethod !== false && + obj !== Boolean && obj !== Object && obj !== Number && obj !== Array && obj !== Date && obj !== String; + } + + var CONTINUE = {}; + + function mixinProperties(mixinsMeta, mixin) { + var guid; + + if (mixin instanceof Mixin) { + guid = guidFor(mixin); + if (mixinsMeta[guid]) { return CONTINUE; } + mixinsMeta[guid] = mixin; + return mixin.properties; + } else { + return mixin; // apply anonymous mixin properties + } + } + + function concatenatedMixinProperties(concatProp, props, values, base) { + var concats; + + // reset before adding each new mixin to pickup concats from previous + concats = values[concatProp] || base[concatProp]; + if (props[concatProp]) { + concats = concats ? concats.concat(props[concatProp]) : props[concatProp]; + } + + return concats; + } + + function giveDescriptorSuper(meta, key, property, values, descs) { + var superProperty; + + // Computed properties override methods, and do not call super to them + if (values[key] === undefined) { + // Find the original descriptor in a parent mixin + superProperty = descs[key]; + } + + // If we didn't find the original descriptor in a parent mixin, find + // it on the original object. + superProperty = superProperty || meta.descs[key]; + + if (superProperty === undefined || !(superProperty instanceof ComputedProperty)) { + return property; + } + + // Since multiple mixins may inherit from the same parent, we need + // to clone the computed property so that other mixins do not receive + // the wrapped version. + property = o_create(property); + property.func = wrap(property.func, superProperty.func); + + return property; + } + + function giveMethodSuper(obj, key, method, values, descs) { + var superMethod; + + // Methods overwrite computed properties, and do not call super to them. + if (descs[key] === undefined) { + // Find the original method in a parent mixin + superMethod = values[key]; + } + + // If we didn't find the original value in a parent mixin, find it in + // the original object + superMethod = superMethod || obj[key]; + + // Only wrap the new method if the original method was a function + if (superMethod === undefined || 'function' !== typeof superMethod) { + return method; + } + + return wrap(method, superMethod); + } + + function applyConcatenatedProperties(obj, key, value, values) { + var baseValue = values[key] || obj[key]; + + if (baseValue) { + if ('function' === typeof baseValue.concat) { + return baseValue.concat(value); + } else { + return makeArray(baseValue).concat(value); + } + } else { + return makeArray(value); + } + } + + function applyMergedProperties(obj, key, value, values) { + var baseValue = values[key] || obj[key]; + + Ember.assert("You passed in `" + JSON.stringify(value) + "` as the value for `" + key + + "` but `" + key + "` cannot be an Array", !isArray(value)); + + if (!baseValue) { return value; } + + var newBase = merge({}, baseValue); + var hasFunction = false; + + for (var prop in value) { + if (!value.hasOwnProperty(prop)) { continue; } + + var propValue = value[prop]; + if (isMethod(propValue)) { + // TODO: support for Computed Properties, etc? + hasFunction = true; + newBase[prop] = giveMethodSuper(obj, prop, propValue, baseValue, {}); + } else { + newBase[prop] = propValue; + } + } + + if (hasFunction) { + newBase._super = superFunction; + } + + return newBase; + } + + function addNormalizedProperty(base, key, value, meta, descs, values, concats, mergings) { + if (value instanceof Descriptor) { + if (value === REQUIRED && descs[key]) { return CONTINUE; } + + // Wrap descriptor function to implement + // __nextSuper() if needed + if (value.func) { + value = giveDescriptorSuper(meta, key, value, values, descs); + } + + descs[key] = value; + values[key] = undefined; + } else { + if ((concats && a_indexOf.call(concats, key) >= 0) || + key === 'concatenatedProperties' || + key === 'mergedProperties') { + value = applyConcatenatedProperties(base, key, value, values); + } else if ((mergings && a_indexOf.call(mergings, key) >= 0)) { + value = applyMergedProperties(base, key, value, values); + } else if (isMethod(value)) { + value = giveMethodSuper(base, key, value, values, descs); + } + + descs[key] = undefined; + values[key] = value; + } + } + + function mergeMixins(mixins, m, descs, values, base, keys) { + var mixin, props, key, concats, mergings, meta; + + function removeKeys(keyName) { + delete descs[keyName]; + delete values[keyName]; + } + + for(var i=0, l=mixins.length; i= 0) { + if (_detect(mixins[loc], targetMixin, seen)) { return true; } + } + return false; + } + + /** + @method detect + @param obj + @return {Boolean} + */ + MixinPrototype.detect = function(obj) { + if (!obj) { return false; } + if (obj instanceof Mixin) { return _detect(obj, this, {}); } + var m = obj['__ember_meta__']; + var mixins = m && m.mixins; + if (mixins) { + return !!mixins[guidFor(this)]; + } + return false; + }; + + MixinPrototype.without = function() { + var ret = new Mixin(this); + ret._without = a_slice.call(arguments); + return ret; + }; + + function _keys(ret, mixin, seen) { + if (seen[guidFor(mixin)]) { return; } + seen[guidFor(mixin)] = true; + + if (mixin.properties) { + var props = mixin.properties; + for (var key in props) { + if (props.hasOwnProperty(key)) { ret[key] = true; } + } + } else if (mixin.mixins) { + a_forEach.call(mixin.mixins, function(x) { _keys(ret, x, seen); }); + } + } + + MixinPrototype.keys = function() { + var keys = {}; + var seen = {}; + var ret = []; + _keys(keys, this, seen); + for(var key in keys) { + if (keys.hasOwnProperty(key)) { ret.push(key); } + } + return ret; + }; + + // returns the mixins currently applied to the specified object + // TODO: Make Ember.mixin + Mixin.mixins = function(obj) { + var m = obj['__ember_meta__']; + var mixins = m && m.mixins; + var ret = []; + + if (!mixins) { return ret; } + + for (var key in mixins) { + var mixin = mixins[key]; + + // skip primitive mixins since these are always anonymous + if (!mixin.properties) { ret.push(mixin); } + } + + return ret; + }; + + REQUIRED = new Descriptor(); + REQUIRED.toString = function() { return '(Required Property)'; }; + + /** + Denotes a required property for a mixin + + @method required + @for Ember + */ + function required() { + return REQUIRED; + } + + __exports__.required = required;function Alias(methodName) { + this.methodName = methodName; + } + + Alias.prototype = new Descriptor(); + + /** + Makes a method available via an additional name. + + ```javascript + App.Person = Ember.Object.extend({ + name: function() { + return 'Tomhuda Katzdale'; + }, + moniker: Ember.aliasMethod('name') + }); + + var goodGuy = App.Person.create(); + + goodGuy.name(); // 'Tomhuda Katzdale' + goodGuy.moniker(); // 'Tomhuda Katzdale' + ``` + + @method aliasMethod + @for Ember + @param {String} methodName name of the method to alias + @return {Ember.Descriptor} + */ + function aliasMethod(methodName) { + return new Alias(methodName); + } + + __exports__.aliasMethod = aliasMethod;// .......................................................... + // OBSERVER HELPER + // + + /** + Specify a method that observes property changes. + + ```javascript + Ember.Object.extend({ + valueObserver: Ember.observer('value', function() { + // Executes whenever the "value" property changes + }) + }); + ``` + + In the future this method may become asynchronous. If you want to ensure + synchronous behavior, use `immediateObserver`. + + Also available as `Function.prototype.observes` if prototype extensions are + enabled. + + @method observer + @for Ember + @param {String} propertyNames* + @param {Function} func + @return func + */ + function observer() { + var func = a_slice.call(arguments, -1)[0]; + var paths; + + var addWatchedProperty = function (path) { paths.push(path); }; + var _paths = a_slice.call(arguments, 0, -1); + + if (typeof func !== "function") { + // revert to old, soft-deprecated argument ordering + + func = arguments[0]; + _paths = a_slice.call(arguments, 1); + } + + paths = []; + + for (var i=0; i<_paths.length; ++i) { + expandProperties(_paths[i], addWatchedProperty); + } + + if (typeof func !== "function") { + throw new Ember.Error("Ember.observer called without a function"); + } + + func.__ember_observes__ = paths; + return func; + } + + __exports__.observer = observer;/** + Specify a method that observes property changes. + + ```javascript + Ember.Object.extend({ + valueObserver: Ember.immediateObserver('value', function() { + // Executes whenever the "value" property changes + }) + }); + ``` + + In the future, `Ember.observer` may become asynchronous. In this event, + `Ember.immediateObserver` will maintain the synchronous behavior. + + Also available as `Function.prototype.observesImmediately` if prototype extensions are + enabled. + + @method immediateObserver + @for Ember + @param {String} propertyNames* + @param {Function} func + @return func + */ + function immediateObserver() { + for (var i=0, l=arguments.length; i this.changingFrom ? 'green' : 'red'; + // logic + } + }), + + friendsDidChange: Ember.observer('friends.@each.name', function(obj, keyName) { + // some logic + // obj.get(keyName) returns friends array + }) + }); + ``` + + Also available as `Function.prototype.observesBefore` if prototype extensions are + enabled. + + @method beforeObserver + @for Ember + @param {String} propertyNames* + @param {Function} func + @return func + */ + function beforeObserver() { + var func = a_slice.call(arguments, -1)[0]; + var paths; + + var addWatchedProperty = function(path) { paths.push(path); }; + + var _paths = a_slice.call(arguments, 0, -1); + + if (typeof func !== "function") { + // revert to old, soft-deprecated argument ordering + + func = arguments[0]; + _paths = a_slice.call(arguments, 1); + } + + paths = []; + + for (var i=0; i<_paths.length; ++i) { + expandProperties(_paths[i], addWatchedProperty); + } + + if (typeof func !== "function") { + throw new Ember.Error("Ember.beforeObserver called without a function"); + } + + func.__ember_observesBefore__ = paths; + return func; + } + + __exports__.beforeObserver = beforeObserver;__exports__.IS_BINDING = IS_BINDING; + __exports__.Mixin = Mixin; + }); +enifed("ember-metal/observer", + ["ember-metal/watching","ember-metal/array","ember-metal/events","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var watch = __dependency1__.watch; + var unwatch = __dependency1__.unwatch; + var map = __dependency2__.map; + var listenersFor = __dependency3__.listenersFor; + var addListener = __dependency3__.addListener; + var removeListener = __dependency3__.removeListener; + var suspendListeners = __dependency3__.suspendListeners; + var suspendListener = __dependency3__.suspendListener; + /** + @module ember-metal + */ + + var AFTER_OBSERVERS = ':change'; + var BEFORE_OBSERVERS = ':before'; + + function changeEvent(keyName) { + return keyName + AFTER_OBSERVERS; + } + + function beforeEvent(keyName) { + return keyName + BEFORE_OBSERVERS; + } + + /** + @method addObserver + @for Ember + @param obj + @param {String} path + @param {Object|Function} targetOrMethod + @param {Function|String} [method] + */ + function addObserver(obj, _path, target, method) { + addListener(obj, changeEvent(_path), target, method); + watch(obj, _path); + + return this; + } + + __exports__.addObserver = addObserver;function observersFor(obj, path) { + return listenersFor(obj, changeEvent(path)); + } + + __exports__.observersFor = observersFor;/** + @method removeObserver + @for Ember + @param obj + @param {String} path + @param {Object|Function} targetOrMethod + @param {Function|String} [method] + */ + function removeObserver(obj, _path, target, method) { + unwatch(obj, _path); + removeListener(obj, changeEvent(_path), target, method); + + return this; + } + + __exports__.removeObserver = removeObserver;/** + @method addBeforeObserver + @for Ember + @param obj + @param {String} path + @param {Object|Function} targetOrMethod + @param {Function|String} [method] + */ + function addBeforeObserver(obj, _path, target, method) { + addListener(obj, beforeEvent(_path), target, method); + watch(obj, _path); + + return this; + } + + __exports__.addBeforeObserver = addBeforeObserver;// Suspend observer during callback. + // + // This should only be used by the target of the observer + // while it is setting the observed path. + function _suspendBeforeObserver(obj, path, target, method, callback) { + return suspendListener(obj, beforeEvent(path), target, method, callback); + } + + __exports__._suspendBeforeObserver = _suspendBeforeObserver;function _suspendObserver(obj, path, target, method, callback) { + return suspendListener(obj, changeEvent(path), target, method, callback); + } + + __exports__._suspendObserver = _suspendObserver;function _suspendBeforeObservers(obj, paths, target, method, callback) { + var events = map.call(paths, beforeEvent); + return suspendListeners(obj, events, target, method, callback); + } + + __exports__._suspendBeforeObservers = _suspendBeforeObservers;function _suspendObservers(obj, paths, target, method, callback) { + var events = map.call(paths, changeEvent); + return suspendListeners(obj, events, target, method, callback); + } + + __exports__._suspendObservers = _suspendObservers;function beforeObserversFor(obj, path) { + return listenersFor(obj, beforeEvent(path)); + } + + __exports__.beforeObserversFor = beforeObserversFor;/** + @method removeBeforeObserver + @for Ember + @param obj + @param {String} path + @param {Object|Function} targetOrMethod + @param {Function|String} [method] + */ + function removeBeforeObserver(obj, _path, target, method) { + unwatch(obj, _path); + removeListener(obj, beforeEvent(_path), target, method); + + return this; + } + + __exports__.removeBeforeObserver = removeBeforeObserver; + }); +enifed("ember-metal/observer_set", + ["ember-metal/utils","ember-metal/events","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var guidFor = __dependency1__.guidFor; + var sendEvent = __dependency2__.sendEvent; + + /* + this.observerSet = { + [senderGuid]: { // variable name: `keySet` + [keyName]: listIndex + } + }, + this.observers = [ + { + sender: obj, + keyName: keyName, + eventName: eventName, + listeners: [ + [target, method, flags] + ] + }, + ... + ] + */ + __exports__["default"] = ObserverSet; + function ObserverSet() { + this.clear(); + } + + + ObserverSet.prototype.add = function(sender, keyName, eventName) { + var observerSet = this.observerSet; + var observers = this.observers; + var senderGuid = guidFor(sender); + var keySet = observerSet[senderGuid]; + var index; + + if (!keySet) { + observerSet[senderGuid] = keySet = {}; + } + index = keySet[keyName]; + if (index === undefined) { + index = observers.push({ + sender: sender, + keyName: keyName, + eventName: eventName, + listeners: [] + }) - 1; + keySet[keyName] = index; + } + return observers[index].listeners; + }; + + ObserverSet.prototype.flush = function() { + var observers = this.observers; + var i, len, observer, sender; + this.clear(); + for (i=0, len=observers.length; i < len; ++i) { + observer = observers[i]; + sender = observer.sender; + if (sender.isDestroying || sender.isDestroyed) { continue; } + sendEvent(sender, observer.eventName, [sender, observer.keyName], observer.listeners); + } + }; + + ObserverSet.prototype.clear = function() { + this.observerSet = {}; + this.observers = []; + }; + }); +enifed("ember-metal/path_cache", + ["ember-metal/cache","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Cache = __dependency1__["default"]; + + var IS_GLOBAL = /^([A-Z$]|([0-9][A-Z$]))/; + var IS_GLOBAL_PATH = /^([A-Z$]|([0-9][A-Z$])).*[\.]/; + var HAS_THIS = 'this.'; + + var isGlobalCache = new Cache(1000, function(key) { return IS_GLOBAL.test(key); }); + var isGlobalPathCache = new Cache(1000, function(key) { return IS_GLOBAL_PATH.test(key); }); + var hasThisCache = new Cache(1000, function(key) { return key.indexOf(HAS_THIS) !== -1; }); + var isPathCache = new Cache(1000, function(key) { return key.indexOf('.') !== -1; }); + + var caches = { + isGlobalCache: isGlobalCache, + isGlobalPathCache: isGlobalPathCache, + hasThisCache: hasThisCache, + isPathCache: isPathCache + }; + __exports__.caches = caches; + function isGlobal(path) { + return isGlobalCache.get(path); + } + + __exports__.isGlobal = isGlobal;function isGlobalPath(path) { + return isGlobalPathCache.get(path); + } + + __exports__.isGlobalPath = isGlobalPath;function hasThis(path) { + return hasThisCache.get(path); + } + + __exports__.hasThis = hasThis;function isPath(path) { + return isPathCache.get(path); + } + + __exports__.isPath = isPath; + }); +enifed("ember-metal/platform", + ["ember-metal/platform/define_property","ember-metal/platform/define_properties","ember-metal/platform/create","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var hasES5CompliantDefineProperty = __dependency1__.hasES5CompliantDefineProperty; + var defineProperty = __dependency1__.defineProperty; + var defineProperties = __dependency2__["default"]; + var create = __dependency3__["default"]; + + /** + @module ember-metal + */ + + var hasPropertyAccessors = hasES5CompliantDefineProperty; + var canDefineNonEnumerableProperties = hasES5CompliantDefineProperty; + + /** + Platform specific methods and feature detectors needed by the framework. + + @class platform + @namespace Ember + @static + */ + + __exports__.create = create; + __exports__.defineProperty = defineProperty; + __exports__.defineProperties = defineProperties; + __exports__.hasPropertyAccessors = hasPropertyAccessors; + __exports__.canDefineNonEnumerableProperties = canDefineNonEnumerableProperties; + }); +enifed("ember-metal/platform/create", + ["exports"], + function(__exports__) { + // Remove "use strict"; from transpiled module until + // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed + // + // REMOVE_USE_STRICT: true + + /** + @class platform + @namespace Ember + @static + */ + + /** + Identical to `Object.create()`. Implements if not available natively. + + @method create + @for Ember + */ + var create; + // ES5 15.2.3.5 + // http://es5.github.com/#x15.2.3.5 + if (!(Object.create && !Object.create(null).hasOwnProperty)) { + /* jshint scripturl:true, proto:true */ + // Contributed by Brandon Benvie, October, 2012 + var createEmpty; + var supportsProto = !({'__proto__':null} instanceof Object); + // the following produces false positives + // in Opera Mini => not a reliable check + // Object.prototype.__proto__ === null + if (supportsProto || typeof document === 'undefined') { + createEmpty = function () { + return { "__proto__": null }; + }; + } else { + // In old IE __proto__ can't be used to manually set `null`, nor does + // any other method exist to make an object that inherits from nothing, + // aside from Object.prototype itself. Instead, create a new global + // object and *steal* its Object.prototype and strip it bare. This is + // used as the prototype to create nullary objects. + createEmpty = function () { + var iframe = document.createElement('iframe'); + var parent = document.body || document.documentElement; + iframe.style.display = 'none'; + parent.appendChild(iframe); + iframe.src = 'javascript:'; + var empty = iframe.contentWindow.Object.prototype; + parent.removeChild(iframe); + iframe = null; + delete empty.constructor; + delete empty.hasOwnProperty; + delete empty.propertyIsEnumerable; + delete empty.isPrototypeOf; + delete empty.toLocaleString; + delete empty.toString; + delete empty.valueOf; + + function Empty() {} + Empty.prototype = empty; + // short-circuit future calls + createEmpty = function () { + return new Empty(); + }; + return new Empty(); + }; + } + + create = Object.create = function create(prototype, properties) { + + var object; + function Type() {} // An empty constructor. + + if (prototype === null) { + object = createEmpty(); + } else { + if (typeof prototype !== "object" && typeof prototype !== "function") { + // In the native implementation `parent` can be `null` + // OR *any* `instanceof Object` (Object|Function|Array|RegExp|etc) + // Use `typeof` tho, b/c in old IE, DOM elements are not `instanceof Object` + // like they are in modern browsers. Using `Object.create` on DOM elements + // is...err...probably inappropriate, but the native version allows for it. + throw new TypeError("Object prototype may only be an Object or null"); // same msg as Chrome + } + + Type.prototype = prototype; + + object = new Type(); + } + + if (properties !== undefined) { + Object.defineProperties(object, properties); + } + + return object; + }; + } else { + create = Object.create; + } + + __exports__["default"] = create; + }); +enifed("ember-metal/platform/define_properties", + ["ember-metal/platform/define_property","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var defineProperty = __dependency1__.defineProperty; + + var defineProperties = Object.defineProperties; + + // ES5 15.2.3.7 + // http://es5.github.com/#x15.2.3.7 + if (!defineProperties) { + defineProperties = function defineProperties(object, properties) { + for (var property in properties) { + if (properties.hasOwnProperty(property) && property !== "__proto__") { + defineProperty(object, property, properties[property]); + } + } + return object; + }; + + Object.defineProperties = defineProperties; + } + + __exports__["default"] = defineProperties; + }); +enifed("ember-metal/platform/define_property", + ["exports"], + function(__exports__) { + "use strict"; + /*globals Node */ + + /** + @class platform + @namespace Ember + @static + */ + + /** + Set to true if the platform supports native getters and setters. + + @property hasPropertyAccessors + @final + */ + + /** + Identical to `Object.defineProperty()`. Implements as much functionality + as possible if not available natively. + + @method defineProperty + @param {Object} obj The object to modify + @param {String} keyName property name to modify + @param {Object} desc descriptor hash + @return {void} + */ + var defineProperty = (function checkCompliance(defineProperty) { + if (!defineProperty) return; + try { + var a = 5; + var obj = {}; + defineProperty(obj, 'a', { + configurable: true, + enumerable: true, + get: function () { + return a; + }, + set: function (v) { + a = v; + } + }); + if (obj.a !== 5) return; + obj.a = 10; + if (a !== 10) return; + + // check non-enumerability + defineProperty(obj, 'a', { + configurable: true, + enumerable: false, + writable: true, + value: true + }); + for (var key in obj) { + if (key === 'a') return; + } + + // Detects a bug in Android <3.2 where you cannot redefine a property using + // Object.defineProperty once accessors have already been set. + if (obj.a !== true) return; + + // defineProperty is compliant + return defineProperty; + } catch (e) { + // IE8 defines Object.defineProperty but calling it on an Object throws + return; + } + })(Object.defineProperty); + + var hasES5CompliantDefineProperty = !!defineProperty; + + if (hasES5CompliantDefineProperty && typeof document !== 'undefined') { + // This is for Safari 5.0, which supports Object.defineProperty, but not + // on DOM nodes. + var canDefinePropertyOnDOM = (function() { + try { + defineProperty(document.createElement('div'), 'definePropertyOnDOM', {}); + return true; + } catch(e) { } + + return false; + })(); + + if (!canDefinePropertyOnDOM) { + defineProperty = function(obj, keyName, desc) { + var isNode; + + if (typeof Node === "object") { + isNode = obj instanceof Node; + } else { + isNode = typeof obj === "object" && typeof obj.nodeType === "number" && typeof obj.nodeName === "string"; + } + + if (isNode) { + // TODO: Should we have a warning here? + return (obj[keyName] = desc.value); + } else { + return Object.defineProperty(obj, keyName, desc); + } + }; + } + } + + if (!hasES5CompliantDefineProperty) { + defineProperty = function defineProperty(obj, keyName, desc) { + if (!desc.get) { obj[keyName] = desc.value; } + }; + } + + __exports__.hasES5CompliantDefineProperty = hasES5CompliantDefineProperty; + __exports__.defineProperty = defineProperty; + }); +enifed("ember-metal/properties", + ["ember-metal/core","ember-metal/utils","ember-metal/platform","ember-metal/property_events","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + /** + @module ember-metal + */ + + var Ember = __dependency1__["default"]; + var metaFor = __dependency2__.meta; + var objectDefineProperty = __dependency3__.defineProperty; + var hasPropertyAccessors = __dependency3__.hasPropertyAccessors; + var overrideChains = __dependency4__.overrideChains; + // .......................................................... + // DESCRIPTOR + // + + /** + Objects of this type can implement an interface to respond to requests to + get and set. The default implementation handles simple properties. + + You generally won't need to create or subclass this directly. + + @class Descriptor + @namespace Ember + @private + @constructor + */ + function Descriptor() {} + + __exports__.Descriptor = Descriptor;// .......................................................... + // DEFINING PROPERTIES API + // + + function MANDATORY_SETTER_FUNCTION(name) { + return function SETTER_FUNCTION(value) { + Ember.assert("You must use Ember.set() to set the `" + name + "` property (of " + this + ") to `" + value + "`.", false); + }; + } + + __exports__.MANDATORY_SETTER_FUNCTION = MANDATORY_SETTER_FUNCTION;function DEFAULT_GETTER_FUNCTION(name) { + return function GETTER_FUNCTION() { + var meta = this['__ember_meta__']; + return meta && meta.values[name]; + }; + } + + __exports__.DEFAULT_GETTER_FUNCTION = DEFAULT_GETTER_FUNCTION;/** + NOTE: This is a low-level method used by other parts of the API. You almost + never want to call this method directly. Instead you should use + `Ember.mixin()` to define new properties. + + Defines a property on an object. This method works much like the ES5 + `Object.defineProperty()` method except that it can also accept computed + properties and other special descriptors. + + Normally this method takes only three parameters. However if you pass an + instance of `Ember.Descriptor` as the third param then you can pass an + optional value as the fourth parameter. This is often more efficient than + creating new descriptor hashes for each property. + + ## Examples + + ```javascript + // ES5 compatible mode + Ember.defineProperty(contact, 'firstName', { + writable: true, + configurable: false, + enumerable: true, + value: 'Charles' + }); + + // define a simple property + Ember.defineProperty(contact, 'lastName', undefined, 'Jolley'); + + // define a computed property + Ember.defineProperty(contact, 'fullName', Ember.computed(function() { + return this.firstName+' '+this.lastName; + }).property('firstName', 'lastName')); + ``` + + @private + @method defineProperty + @for Ember + @param {Object} obj the object to define this property on. This may be a prototype. + @param {String} keyName the name of the property + @param {Ember.Descriptor} [desc] an instance of `Ember.Descriptor` (typically a + computed property) or an ES5 descriptor. + You must provide this or `data` but not both. + @param {*} [data] something other than a descriptor, that will + become the explicit value of this property. + */ + function defineProperty(obj, keyName, desc, data, meta) { + var descs, existingDesc, watching, value; + + if (!meta) meta = metaFor(obj); + descs = meta.descs; + existingDesc = meta.descs[keyName]; + var watchEntry = meta.watching[keyName]; + + watching = watchEntry !== undefined && watchEntry > 0; + + if (existingDesc instanceof Descriptor) { + existingDesc.teardown(obj, keyName); + } + + if (desc instanceof Descriptor) { + value = desc; + + descs[keyName] = desc; + + if (watching && hasPropertyAccessors) { + objectDefineProperty(obj, keyName, { + configurable: true, + enumerable: true, + writable: true, + value: undefined // make enumerable + }); + } else { + obj[keyName] = undefined; // make enumerable + } + if (desc.setup) { desc.setup(obj, keyName); } + } else { + descs[keyName] = undefined; // shadow descriptor in proto + if (desc == null) { + value = data; + + + if (watching && hasPropertyAccessors) { + meta.values[keyName] = data; + objectDefineProperty(obj, keyName, { + configurable: true, + enumerable: true, + set: MANDATORY_SETTER_FUNCTION(keyName), + get: DEFAULT_GETTER_FUNCTION(keyName) + }); + } else { + obj[keyName] = data; + } + } else { + value = desc; + + // compatibility with ES5 + objectDefineProperty(obj, keyName, desc); + } + } + + // if key is being watched, override chains that + // were initialized with the prototype + if (watching) { overrideChains(obj, keyName, meta); } + + // The `value` passed to the `didDefineProperty` hook is + // either the descriptor or data, whichever was passed. + if (obj.didDefineProperty) { obj.didDefineProperty(obj, keyName, value); } + + return this; + } + __exports__.defineProperty = defineProperty; + }); +enifed("ember-metal/property_events", + ["ember-metal/utils","ember-metal/events","ember-metal/observer_set","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var guidFor = __dependency1__.guidFor; + var tryFinally = __dependency1__.tryFinally; + var sendEvent = __dependency2__.sendEvent; + var listenersUnion = __dependency2__.listenersUnion; + var listenersDiff = __dependency2__.listenersDiff; + var ObserverSet = __dependency3__["default"]; + + var beforeObserverSet = new ObserverSet(); + var observerSet = new ObserverSet(); + var deferred = 0; + + // .......................................................... + // PROPERTY CHANGES + // + + /** + This function is called just before an object property is about to change. + It will notify any before observers and prepare caches among other things. + + Normally you will not need to call this method directly but if for some + reason you can't directly watch a property you can invoke this method + manually along with `Ember.propertyDidChange()` which you should call just + after the property value changes. + + @method propertyWillChange + @for Ember + @param {Object} obj The object with the property that will change + @param {String} keyName The property key (or path) that will change. + @return {void} + */ + function propertyWillChange(obj, keyName) { + var m = obj['__ember_meta__']; + var watching = (m && m.watching[keyName] > 0) || keyName === 'length'; + var proto = m && m.proto; + var desc = m && m.descs[keyName]; + + if (!watching) { return; } + if (proto === obj) { return; } + if (desc && desc.willChange) { desc.willChange(obj, keyName); } + dependentKeysWillChange(obj, keyName, m); + chainsWillChange(obj, keyName, m); + notifyBeforeObservers(obj, keyName); + } + + /** + This function is called just after an object property has changed. + It will notify any observers and clear caches among other things. + + Normally you will not need to call this method directly but if for some + reason you can't directly watch a property you can invoke this method + manually along with `Ember.propertyWillChange()` which you should call just + before the property value changes. + + @method propertyDidChange + @for Ember + @param {Object} obj The object with the property that will change + @param {String} keyName The property key (or path) that will change. + @return {void} + */ + function propertyDidChange(obj, keyName) { + var m = obj['__ember_meta__']; + var watching = (m && m.watching[keyName] > 0) || keyName === 'length'; + var proto = m && m.proto; + var desc = m && m.descs[keyName]; + + if (proto === obj) { return; } + + // shouldn't this mean that we're watching this key? + if (desc && desc.didChange) { desc.didChange(obj, keyName); } + if (!watching && keyName !== 'length') { return; } + + if (m && m.deps && m.deps[keyName]) { + dependentKeysDidChange(obj, keyName, m); + } + + chainsDidChange(obj, keyName, m, false); + notifyObservers(obj, keyName); + } + + var WILL_SEEN, DID_SEEN; + // called whenever a property is about to change to clear the cache of any dependent keys (and notify those properties of changes, etc...) + function dependentKeysWillChange(obj, depKey, meta) { + if (obj.isDestroying) { return; } + + var deps; + if (meta && meta.deps && (deps = meta.deps[depKey])) { + var seen = WILL_SEEN; + var top = !seen; + if (top) { seen = WILL_SEEN = {}; } + iterDeps(propertyWillChange, obj, deps, depKey, seen, meta); + if (top) { WILL_SEEN = null; } + } + } + + // called whenever a property has just changed to update dependent keys + function dependentKeysDidChange(obj, depKey, meta) { + if (obj.isDestroying) { return; } + + var deps; + if (meta && meta.deps && (deps = meta.deps[depKey])) { + var seen = DID_SEEN; + var top = !seen; + if (top) { seen = DID_SEEN = {}; } + iterDeps(propertyDidChange, obj, deps, depKey, seen, meta); + if (top) { DID_SEEN = null; } + } + } + + function keysOf(obj) { + var keys = []; + for (var key in obj) keys.push(key); + return keys; + } + + function iterDeps(method, obj, deps, depKey, seen, meta) { + var keys, key, i, desc; + var guid = guidFor(obj); + var current = seen[guid]; + if (!current) current = seen[guid] = {}; + if (current[depKey]) return; + current[depKey] = true; + + if (deps) { + keys = keysOf(deps); + var descs = meta.descs; + for (i=0; i 0) { + ret = meta.values[keyName]; + } else { + ret = obj[keyName]; + } + + if (ret === undefined && + 'object' === typeof obj && !(keyName in obj) && 'function' === typeof obj.unknownProperty) { + return obj.unknownProperty(keyName); + } + + return ret; + } + }; + + // Currently used only by Ember Data tests + if (Ember.config.overrideAccessors) { + Ember.get = get; + Ember.config.overrideAccessors(); + get = Ember.get; + } + + /** + Normalizes a target/path pair to reflect that actual target/path that should + be observed, etc. This takes into account passing in global property + paths (i.e. a path beginning with a captial letter not defined on the + target). + + @private + @method normalizeTuple + @for Ember + @param {Object} target The current target. May be `null`. + @param {String} path A path on the target or a global property path. + @return {Array} a temporary array with the normalized target/path pair. + */ + function normalizeTuple(target, path) { + var hasThis = pathHasThis(path); + var isGlobal = !hasThis && isGlobalPath(path); + var key; + + if (!target || isGlobal) target = Ember.lookup; + if (hasThis) path = path.slice(5); + + Ember.deprecate( + "normalizeTuple will return '"+path+"' as a non-global. This behavior will change in the future (issue #3852)", + target === Ember.lookup || !target || hasThis || isGlobal || !isGlobalPath(path+'.') + ); + + if (target === Ember.lookup) { + key = path.match(FIRST_KEY)[0]; + target = get(target, key); + path = path.slice(key.length+1); + } + + // must return some kind of path to be valid else other things will break. + if (!path || path.length===0) throw new EmberError('Path cannot be empty'); + + return [ target, path ]; + } + + function _getPath(root, path) { + var hasThis, parts, tuple, idx, len; + + // If there is no root and path is a key name, return that + // property from the global object. + // E.g. get('Ember') -> Ember + if (root === null && !isPath(path)) { + return get(Ember.lookup, path); + } + + // detect complicated paths and normalize them + hasThis = pathHasThis(path); + + if (!root || hasThis) { + tuple = normalizeTuple(root, path); + root = tuple[0]; + path = tuple[1]; + tuple.length = 0; + } + + parts = path.split("."); + len = parts.length; + for (idx = 0; root != null && idx < len; idx++) { + root = get(root, parts[idx], true); + if (root && root.isDestroyed) { return undefined; } + } + return root; + } + + function getWithDefault(root, key, defaultValue) { + var value = get(root, key); + + if (value === undefined) { return defaultValue; } + return value; + } + + __exports__.getWithDefault = getWithDefault;__exports__["default"] = get; + __exports__.get = get; + __exports__.normalizeTuple = normalizeTuple; + __exports__._getPath = _getPath; + }); +enifed("ember-metal/property_set", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_events","ember-metal/properties","ember-metal/error","ember-metal/path_cache","ember-metal/platform","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var getPath = __dependency2__._getPath; + var propertyWillChange = __dependency3__.propertyWillChange; + var propertyDidChange = __dependency3__.propertyDidChange; + var defineProperty = __dependency4__.defineProperty; + var EmberError = __dependency5__["default"]; + var isPath = __dependency6__.isPath; + var hasPropertyAccessors = __dependency7__.hasPropertyAccessors; + + var IS_GLOBAL = /^([A-Z$]|([0-9][A-Z$]))/; + + /** + Sets the value of a property on an object, respecting computed properties + and notifying observers and other listeners of the change. If the + property is not defined but the object implements the `setUnknownProperty` + method then that will be invoked as well. + + @method set + @for Ember + @param {Object} obj The object to modify. + @param {String} keyName The property key to set + @param {Object} value The value to set + @return {Object} the passed value. + */ + var set = function set(obj, keyName, value, tolerant) { + if (typeof obj === 'string') { + Ember.assert("Path '" + obj + "' must be global if no obj is given.", IS_GLOBAL.test(obj)); + value = keyName; + keyName = obj; + obj = null; + } + + Ember.assert("Cannot call set with "+ keyName +" key.", !!keyName); + + if (!obj) { + return setPath(obj, keyName, value, tolerant); + } + + var meta = obj['__ember_meta__']; + var desc = meta && meta.descs[keyName]; + var isUnknown, currentValue; + + if (desc === undefined && isPath(keyName)) { + return setPath(obj, keyName, value, tolerant); + } + + Ember.assert("You need to provide an object and key to `set`.", !!obj && keyName !== undefined); + Ember.assert('calling set on destroyed object', !obj.isDestroyed); + + if (desc !== undefined) { + desc.set(obj, keyName, value); + } else { + + if (typeof obj === 'object' && obj !== null && value !== undefined && obj[keyName] === value) { + return value; + } + + isUnknown = 'object' === typeof obj && !(keyName in obj); + + // setUnknownProperty is called if `obj` is an object, + // the property does not already exist, and the + // `setUnknownProperty` method exists on the object + if (isUnknown && 'function' === typeof obj.setUnknownProperty) { + obj.setUnknownProperty(keyName, value); + } else if (meta && meta.watching[keyName] > 0) { + + if (hasPropertyAccessors) { + currentValue = meta.values[keyName]; + } else { + currentValue = obj[keyName]; + } + // only trigger a change if the value has changed + if (value !== currentValue) { + propertyWillChange(obj, keyName); + + if (hasPropertyAccessors) { + if ((currentValue === undefined && !(keyName in obj)) || !obj.propertyIsEnumerable(keyName)) { + defineProperty(obj, keyName, null, value); // setup mandatory setter + } else { + meta.values[keyName] = value; + } + } else { + obj[keyName] = value; + } + propertyDidChange(obj, keyName); + } + } else { + obj[keyName] = value; + } + } + return value; + }; + + // Currently used only by Ember Data tests + // ES6TODO: Verify still true + if (Ember.config.overrideAccessors) { + Ember.set = set; + Ember.config.overrideAccessors(); + set = Ember.set; + } + + function setPath(root, path, value, tolerant) { + var keyName; + + // get the last part of the path + keyName = path.slice(path.lastIndexOf('.') + 1); + + // get the first part of the part + path = (path === keyName) ? keyName : path.slice(0, path.length-(keyName.length+1)); + + // unless the path is this, look up the first part to + // get the root + if (path !== 'this') { + root = getPath(root, path); + } + + if (!keyName || keyName.length === 0) { + throw new EmberError('Property set failed: You passed an empty path'); + } + + if (!root) { + if (tolerant) { return; } + else { throw new EmberError('Property set failed: object in path "'+path+'" could not be found or was destroyed.'); } + } + + return set(root, keyName, value); + } + + /** + Error-tolerant form of `Ember.set`. Will not blow up if any part of the + chain is `undefined`, `null`, or destroyed. + + This is primarily used when syncing bindings, which may try to update after + an object has been destroyed. + + @method trySet + @for Ember + @param {Object} obj The object to modify. + @param {String} path The property path to set + @param {Object} value The value to set + */ + function trySet(root, path, value) { + return set(root, path, value, true); + } + + __exports__.trySet = trySet;__exports__.set = set; + }); +enifed("ember-metal/run_loop", + ["ember-metal/core","ember-metal/utils","ember-metal/array","ember-metal/property_events","backburner","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var apply = __dependency2__.apply; + var GUID_KEY = __dependency2__.GUID_KEY; + var indexOf = __dependency3__.indexOf; + var beginPropertyChanges = __dependency4__.beginPropertyChanges; + var endPropertyChanges = __dependency4__.endPropertyChanges; + var Backburner = __dependency5__["default"]; + + function onBegin(current) { + run.currentRunLoop = current; + } + + function onEnd(current, next) { + run.currentRunLoop = next; + } + + // ES6TODO: should Backburner become es6? + var backburner = new Backburner(['sync', 'actions', 'destroy'], { + GUID_KEY: GUID_KEY, + sync: { + before: beginPropertyChanges, + after: endPropertyChanges + }, + defaultQueue: 'actions', + onBegin: onBegin, + onEnd: onEnd, + onErrorTarget: Ember, + onErrorMethod: 'onerror' + }); + var slice = [].slice; + var concat = [].concat; + + // .......................................................... + // run - this is ideally the only public API the dev sees + // + + /** + Runs the passed target and method inside of a RunLoop, ensuring any + deferred actions including bindings and views updates are flushed at the + end. + + Normally you should not need to invoke this method yourself. However if + you are implementing raw event handlers when interfacing with other + libraries or plugins, you should probably wrap all of your code inside this + call. + + ```javascript + run(function() { + // code to be execute within a RunLoop + }); + ``` + + @class run + @namespace Ember + @static + @constructor + @param {Object} [target] target of method to call + @param {Function|String} method Method to invoke. + May be a function or a string. If you pass a string + then it will be looked up on the passed target. + @param {Object} [args*] Any additional arguments you wish to pass to the method. + @return {Object} return value from invoking the passed function. + */ + __exports__["default"] = run; + function run() { + return backburner.run.apply(backburner, arguments); + } + + /** + If no run-loop is present, it creates a new one. If a run loop is + present it will queue itself to run on the existing run-loops action + queue. + + Please note: This is not for normal usage, and should be used sparingly. + + If invoked when not within a run loop: + + ```javascript + run.join(function() { + // creates a new run-loop + }); + ``` + + Alternatively, if called within an existing run loop: + + ```javascript + run(function() { + // creates a new run-loop + run.join(function() { + // joins with the existing run-loop, and queues for invocation on + // the existing run-loops action queue. + }); + }); + ``` + + @method join + @namespace Ember + @param {Object} [target] target of method to call + @param {Function|String} method Method to invoke. + May be a function or a string. If you pass a string + then it will be looked up on the passed target. + @param {Object} [args*] Any additional arguments you wish to pass to the method. + @return {Object} Return value from invoking the passed function. Please note, + when called within an existing loop, no return value is possible. + */ + run.join = function(target, method /* args */) { + if (!run.currentRunLoop) { + return Ember.run.apply(Ember, arguments); + } + + var args = slice.call(arguments); + args.unshift('actions'); + run.schedule.apply(run, args); + }; + + /** + Provides a useful utility for when integrating with non-Ember libraries + that provide asynchronous callbacks. + + Ember utilizes a run-loop to batch and coalesce changes. This works by + marking the start and end of Ember-related Javascript execution. + + When using events such as a View's click handler, Ember wraps the event + handler in a run-loop, but when integrating with non-Ember libraries this + can be tedious. + + For example, the following is rather verbose but is the correct way to combine + third-party events and Ember code. + + ```javascript + var that = this; + jQuery(window).on('resize', function(){ + run(function(){ + that.handleResize(); + }); + }); + ``` + + To reduce the boilerplate, the following can be used to construct a + run-loop-wrapped callback handler. + + ```javascript + jQuery(window).on('resize', run.bind(this, this.handleResize)); + ``` + + @method bind + @namespace Ember + @param {Object} [target] target of method to call + @param {Function|String} method Method to invoke. + May be a function or a string. If you pass a string + then it will be looked up on the passed target. + @param {Object} [args*] Any additional arguments you wish to pass to the method. + @return {Object} return value from invoking the passed function. Please note, + when called within an existing loop, no return value is possible. + @since 1.4.0 + */ + run.bind = function(target, method /* args*/) { + var args = slice.call(arguments); + return function() { + return run.join.apply(run, args.concat(slice.call(arguments))); + }; + }; + + run.backburner = backburner; + run.currentRunLoop = null; + run.queues = backburner.queueNames; + + /** + Begins a new RunLoop. Any deferred actions invoked after the begin will + be buffered until you invoke a matching call to `run.end()`. This is + a lower-level way to use a RunLoop instead of using `run()`. + + ```javascript + run.begin(); + // code to be execute within a RunLoop + run.end(); + ``` + + @method begin + @return {void} + */ + run.begin = function() { + backburner.begin(); + }; + + /** + Ends a RunLoop. This must be called sometime after you call + `run.begin()` to flush any deferred actions. This is a lower-level way + to use a RunLoop instead of using `run()`. + + ```javascript + run.begin(); + // code to be execute within a RunLoop + run.end(); + ``` + + @method end + @return {void} + */ + run.end = function() { + backburner.end(); + }; + + /** + Array of named queues. This array determines the order in which queues + are flushed at the end of the RunLoop. You can define your own queues by + simply adding the queue name to this array. Normally you should not need + to inspect or modify this property. + + @property queues + @type Array + @default ['sync', 'actions', 'destroy'] + */ + + /** + Adds the passed target/method and any optional arguments to the named + queue to be executed at the end of the RunLoop. If you have not already + started a RunLoop when calling this method one will be started for you + automatically. + + At the end of a RunLoop, any methods scheduled in this way will be invoked. + Methods will be invoked in an order matching the named queues defined in + the `run.queues` property. + + ```javascript + run.schedule('sync', this, function() { + // this will be executed in the first RunLoop queue, when bindings are synced + console.log("scheduled on sync queue"); + }); + + run.schedule('actions', this, function() { + // this will be executed in the 'actions' queue, after bindings have synced. + console.log("scheduled on actions queue"); + }); + + // Note the functions will be run in order based on the run queues order. + // Output would be: + // scheduled on sync queue + // scheduled on actions queue + ``` + + @method schedule + @param {String} queue The name of the queue to schedule against. + Default queues are 'sync' and 'actions' + @param {Object} [target] target object to use as the context when invoking a method. + @param {String|Function} method The method to invoke. If you pass a string it + will be resolved on the target object at the time the scheduled item is + invoked allowing you to change the target function. + @param {Object} [arguments*] Optional arguments to be passed to the queued method. + @return {void} + */ + run.schedule = function(queue, target, method) { + checkAutoRun(); + backburner.schedule.apply(backburner, arguments); + }; + + // Used by global test teardown + run.hasScheduledTimers = function() { + return backburner.hasTimers(); + }; + + // Used by global test teardown + run.cancelTimers = function () { + backburner.cancelTimers(); + }; + + /** + Immediately flushes any events scheduled in the 'sync' queue. Bindings + use this queue so this method is a useful way to immediately force all + bindings in the application to sync. + + You should call this method anytime you need any changed state to propagate + throughout the app immediately without repainting the UI (which happens + in the later 'render' queue added by the `ember-views` package). + + ```javascript + run.sync(); + ``` + + @method sync + @return {void} + */ + run.sync = function() { + if (backburner.currentInstance) { + backburner.currentInstance.queues.sync.flush(); + } + }; + + /** + Invokes the passed target/method and optional arguments after a specified + period of time. The last parameter of this method must always be a number + of milliseconds. + + You should use this method whenever you need to run some action after a + period of time instead of using `setTimeout()`. This method will ensure that + items that expire during the same script execution cycle all execute + together, which is often more efficient than using a real setTimeout. + + ```javascript + run.later(myContext, function() { + // code here will execute within a RunLoop in about 500ms with this == myContext + }, 500); + ``` + + @method later + @param {Object} [target] target of method to invoke + @param {Function|String} method The method to invoke. + If you pass a string it will be resolved on the + target at the time the method is invoked. + @param {Object} [args*] Optional arguments to pass to the timeout. + @param {Number} wait Number of milliseconds to wait. + @return {Object} Timer information for use in cancelling, see `run.cancel`. + */ + run.later = function(/*target, method*/) { + return backburner.later.apply(backburner, arguments); + }; + + /** + Schedule a function to run one time during the current RunLoop. This is equivalent + to calling `scheduleOnce` with the "actions" queue. + + @method once + @param {Object} [target] The target of the method to invoke. + @param {Function|String} method The method to invoke. + If you pass a string it will be resolved on the + target at the time the method is invoked. + @param {Object} [args*] Optional arguments to pass to the timeout. + @return {Object} Timer information for use in cancelling, see `run.cancel`. + */ + run.once = function(target, method) { + checkAutoRun(); + var args = slice.call(arguments); + args.unshift('actions'); + return apply(backburner, backburner.scheduleOnce, args); + }; + + /** + Schedules a function to run one time in a given queue of the current RunLoop. + Calling this method with the same queue/target/method combination will have + no effect (past the initial call). + + Note that although you can pass optional arguments these will not be + considered when looking for duplicates. New arguments will replace previous + calls. + + ```javascript + run(function() { + var sayHi = function() { console.log('hi'); } + run.scheduleOnce('afterRender', myContext, sayHi); + run.scheduleOnce('afterRender', myContext, sayHi); + // sayHi will only be executed once, in the afterRender queue of the RunLoop + }); + ``` + + Also note that passing an anonymous function to `run.scheduleOnce` will + not prevent additional calls with an identical anonymous function from + scheduling the items multiple times, e.g.: + + ```javascript + function scheduleIt() { + run.scheduleOnce('actions', myContext, function() { console.log("Closure"); }); + } + scheduleIt(); + scheduleIt(); + // "Closure" will print twice, even though we're using `run.scheduleOnce`, + // because the function we pass to it is anonymous and won't match the + // previously scheduled operation. + ``` + + Available queues, and their order, can be found at `run.queues` + + @method scheduleOnce + @param {String} [queue] The name of the queue to schedule against. Default queues are 'sync' and 'actions'. + @param {Object} [target] The target of the method to invoke. + @param {Function|String} method The method to invoke. + If you pass a string it will be resolved on the + target at the time the method is invoked. + @param {Object} [args*] Optional arguments to pass to the timeout. + @return {Object} Timer information for use in cancelling, see `run.cancel`. + */ + run.scheduleOnce = function(/*queue, target, method*/) { + checkAutoRun(); + return backburner.scheduleOnce.apply(backburner, arguments); + }; + + /** + Schedules an item to run from within a separate run loop, after + control has been returned to the system. This is equivalent to calling + `run.later` with a wait time of 1ms. + + ```javascript + run.next(myContext, function() { + // code to be executed in the next run loop, + // which will be scheduled after the current one + }); + ``` + + Multiple operations scheduled with `run.next` will coalesce + into the same later run loop, along with any other operations + scheduled by `run.later` that expire right around the same + time that `run.next` operations will fire. + + Note that there are often alternatives to using `run.next`. + For instance, if you'd like to schedule an operation to happen + after all DOM element operations have completed within the current + run loop, you can make use of the `afterRender` run loop queue (added + by the `ember-views` package, along with the preceding `render` queue + where all the DOM element operations happen). Example: + + ```javascript + App.MyCollectionView = Ember.CollectionView.extend({ + didInsertElement: function() { + run.scheduleOnce('afterRender', this, 'processChildElements'); + }, + processChildElements: function() { + // ... do something with collectionView's child view + // elements after they've finished rendering, which + // can't be done within the CollectionView's + // `didInsertElement` hook because that gets run + // before the child elements have been added to the DOM. + } + }); + ``` + + One benefit of the above approach compared to using `run.next` is + that you will be able to perform DOM/CSS operations before unprocessed + elements are rendered to the screen, which may prevent flickering or + other artifacts caused by delaying processing until after rendering. + + The other major benefit to the above approach is that `run.next` + introduces an element of non-determinism, which can make things much + harder to test, due to its reliance on `setTimeout`; it's much harder + to guarantee the order of scheduled operations when they are scheduled + outside of the current run loop, i.e. with `run.next`. + + @method next + @param {Object} [target] target of method to invoke + @param {Function|String} method The method to invoke. + If you pass a string it will be resolved on the + target at the time the method is invoked. + @param {Object} [args*] Optional arguments to pass to the timeout. + @return {Object} Timer information for use in cancelling, see `run.cancel`. + */ + run.next = function() { + var args = slice.call(arguments); + args.push(1); + return apply(backburner, backburner.later, args); + }; + + /** + Cancels a scheduled item. Must be a value returned by `run.later()`, + `run.once()`, `run.next()`, `run.debounce()`, or + `run.throttle()`. + + ```javascript + var runNext = run.next(myContext, function() { + // will not be executed + }); + run.cancel(runNext); + + var runLater = run.later(myContext, function() { + // will not be executed + }, 500); + run.cancel(runLater); + + var runOnce = run.once(myContext, function() { + // will not be executed + }); + run.cancel(runOnce); + + var throttle = run.throttle(myContext, function() { + // will not be executed + }, 1, false); + run.cancel(throttle); + + var debounce = run.debounce(myContext, function() { + // will not be executed + }, 1); + run.cancel(debounce); + + var debounceImmediate = run.debounce(myContext, function() { + // will be executed since we passed in true (immediate) + }, 100, true); + // the 100ms delay until this method can be called again will be cancelled + run.cancel(debounceImmediate); + ``` + + @method cancel + @param {Object} timer Timer object to cancel + @return {Boolean} true if cancelled or false/undefined if it wasn't found + */ + run.cancel = function(timer) { + return backburner.cancel(timer); + }; + + /** + Delay calling the target method until the debounce period has elapsed + with no additional debounce calls. If `debounce` is called again before + the specified time has elapsed, the timer is reset and the entire period + must pass again before the target method is called. + + This method should be used when an event may be called multiple times + but the action should only be called once when the event is done firing. + A common example is for scroll events where you only want updates to + happen once scrolling has ceased. + + ```javascript + var myFunc = function() { console.log(this.name + ' ran.'); }; + var myContext = {name: 'debounce'}; + + run.debounce(myContext, myFunc, 150); + + // less than 150ms passes + + run.debounce(myContext, myFunc, 150); + + // 150ms passes + // myFunc is invoked with context myContext + // console logs 'debounce ran.' one time. + ``` + + Immediate allows you to run the function immediately, but debounce + other calls for this function until the wait time has elapsed. If + `debounce` is called again before the specified time has elapsed, + the timer is reset and the entire period must pass again before + the method can be called again. + + ```javascript + var myFunc = function() { console.log(this.name + ' ran.'); }; + var myContext = {name: 'debounce'}; + + run.debounce(myContext, myFunc, 150, true); + + // console logs 'debounce ran.' one time immediately. + // 100ms passes + + run.debounce(myContext, myFunc, 150, true); + + // 150ms passes and nothing else is logged to the console and + // the debouncee is no longer being watched + + run.debounce(myContext, myFunc, 150, true); + + // console logs 'debounce ran.' one time immediately. + // 150ms passes and nothing else is logged to the console and + // the debouncee is no longer being watched + + ``` + + @method debounce + @param {Object} [target] target of method to invoke + @param {Function|String} method The method to invoke. + May be a function or a string. If you pass a string + then it will be looked up on the passed target. + @param {Object} [args*] Optional arguments to pass to the timeout. + @param {Number} wait Number of milliseconds to wait. + @param {Boolean} immediate Trigger the function on the leading instead + of the trailing edge of the wait interval. Defaults to false. + @return {Array} Timer information for use in cancelling, see `run.cancel`. + */ + run.debounce = function() { + return backburner.debounce.apply(backburner, arguments); + }; + + /** + Ensure that the target method is never called more frequently than + the specified spacing period. The target method is called immediately. + + ```javascript + var myFunc = function() { console.log(this.name + ' ran.'); }; + var myContext = {name: 'throttle'}; + + run.throttle(myContext, myFunc, 150); + // myFunc is invoked with context myContext + // console logs 'throttle ran.' + + // 50ms passes + run.throttle(myContext, myFunc, 150); + + // 50ms passes + run.throttle(myContext, myFunc, 150); + + // 150ms passes + run.throttle(myContext, myFunc, 150); + // myFunc is invoked with context myContext + // console logs 'throttle ran.' + ``` + + @method throttle + @param {Object} [target] target of method to invoke + @param {Function|String} method The method to invoke. + May be a function or a string. If you pass a string + then it will be looked up on the passed target. + @param {Object} [args*] Optional arguments to pass to the timeout. + @param {Number} spacing Number of milliseconds to space out requests. + @param {Boolean} immediate Trigger the function on the leading instead + of the trailing edge of the wait interval. Defaults to true. + @return {Array} Timer information for use in cancelling, see `run.cancel`. + */ + run.throttle = function() { + return backburner.throttle.apply(backburner, arguments); + }; + + // Make sure it's not an autorun during testing + function checkAutoRun() { + if (!run.currentRunLoop) { + Ember.assert("You have turned on testing mode, which disabled the run-loop's autorun. You will need to wrap any code with asynchronous side-effects in an run", !Ember.testing); + } + } + + /** + Add a new named queue after the specified queue. + + The queue to add will only be added once. + + @method _addQueue + @param {String} name the name of the queue to add. + @param {String} after the name of the queue to add after. + @private + */ + run._addQueue = function(name, after) { + if (indexOf.call(run.queues, name) === -1) { + run.queues.splice(indexOf.call(run.queues, after)+1, 0, name); + } + }; + }); +enifed("ember-metal/set_properties", + ["ember-metal/property_events","ember-metal/property_set","ember-metal/keys","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var changeProperties = __dependency1__.changeProperties; + var set = __dependency2__.set; + var keys = __dependency3__["default"]; + + /** + Set a list of properties on an object. These properties are set inside + a single `beginPropertyChanges` and `endPropertyChanges` batch, so + observers will be buffered. + + ```javascript + var anObject = Ember.Object.create(); + + anObject.setProperties({ + firstName: 'Stanley', + lastName: 'Stuart', + age: 21 + }); + ``` + + @method setProperties + @param obj + @param {Object} properties + @return obj + */ + __exports__["default"] = function setProperties(obj, properties) { + if (!properties || typeof properties !== "object") { return obj; } + changeProperties(function() { + var props = keys(properties); + var propertyName; + + for (var i = 0, l = props.length; i < l; i++) { + propertyName = props[i]; + + set(obj, propertyName, properties[propertyName]); + } + }); + return obj; + } + }); +enifed("ember-metal/utils", + ["ember-metal/core","ember-metal/platform","ember-metal/array","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var o_defineProperty = __dependency2__.defineProperty; + var canDefineNonEnumerableProperties = __dependency2__.canDefineNonEnumerableProperties; + var hasPropertyAccessors = __dependency2__.hasPropertyAccessors; + var create = __dependency2__.create; + + var forEach = __dependency3__.forEach; + + /** + @module ember-metal + */ + + /** + Previously we used `Ember.$.uuid`, however `$.uuid` has been removed from + jQuery master. We'll just bootstrap our own uuid now. + + @private + @return {Number} the uuid + */ + var _uuid = 0; + + /** + Generates a universally unique identifier. This method + is used internally by Ember for assisting with + the generation of GUID's and other unique identifiers + such as `bind-attr` data attributes. + + @public + @return {Number} [description] + */ + function uuid() { + return ++_uuid; + } + + __exports__.uuid = uuid;/** + Prefix used for guids through out Ember. + @private + @property GUID_PREFIX + @for Ember + @type String + @final + */ + var GUID_PREFIX = 'ember'; + + var o_create = create; + // Used for guid generation... + var numberCache = []; + var stringCache = {}; + + /** + Strongly hint runtimes to intern the provided string. + + When do I need to use this function? + + For the most part, never. Pre-mature optimization is bad, and often the + runtime does exactly what you need it to, and more often the trade-off isn't + worth it. + + Why? + + Runtimes store strings in at least 2 different representations: + Ropes and Symbols (interned strings). The Rope provides a memory efficient + data-structure for strings created from concatenation or some other string + manipulation like splitting. + + Unfortunately checking equality of different ropes can be quite costly as + runtimes must resort to clever string comparison algorithims. These + algorithims typically cost in proportion to the length of the string. + Luckily, this is where the Symbols (interned strings) shine. As Symbols are + unique by their string content, equality checks can be done by pointer + comparision. + + How do I know if my string is a rope or symbol? + + Typically (warning general sweeping statement, but truthy in runtimes at + present) static strings created as part of the JS source are interned. + Strings often used for comparisions can be interned at runtime if some + criteria are met. One of these criteria can be the size of the entire rope. + For example, in chrome 38 a rope longer then 12 characters will not + intern, nor will segments of that rope. + + Some numbers: http://jsperf.com/eval-vs-keys/8 + + Known Trick™ + + @private + @return {String} interned version of the provided string + */ + function intern(str) { + var obj = {}; + obj[str] = 1; + for (var key in obj) { + if (key === str) return key; + } + return str; + } + + /** + A unique key used to assign guids and other private metadata to objects. + If you inspect an object in your browser debugger you will often see these. + They can be safely ignored. + + On browsers that support it, these properties are added with enumeration + disabled so they won't show up when you iterate over your properties. + + @private + @property GUID_KEY + @for Ember + @type String + @final + */ + var GUID_KEY = intern('__ember' + (+ new Date())); + + var GUID_DESC = { + writable: false, + configurable: false, + enumerable: false, + value: null + }; + + /** + Generates a new guid, optionally saving the guid to the object that you + pass in. You will rarely need to use this method. Instead you should + call `Ember.guidFor(obj)`, which return an existing guid if available. + + @private + @method generateGuid + @for Ember + @param {Object} [obj] Object the guid will be used for. If passed in, the guid will + be saved on the object and reused whenever you pass the same object + again. + + If no object is passed, just generate a new guid. + @param {String} [prefix] Prefix to place in front of the guid. Useful when you want to + separate the guid into separate namespaces. + @return {String} the guid + */ + function generateGuid(obj, prefix) { + if (!prefix) prefix = GUID_PREFIX; + var ret = (prefix + uuid()); + if (obj) { + if (obj[GUID_KEY] === null) { + obj[GUID_KEY] = ret; + } else { + GUID_DESC.value = ret; + o_defineProperty(obj, GUID_KEY, GUID_DESC); + } + } + return ret; + } + + __exports__.generateGuid = generateGuid;/** + Returns a unique id for the object. If the object does not yet have a guid, + one will be assigned to it. You can call this on any object, + `Ember.Object`-based or not, but be aware that it will add a `_guid` + property. + + You can also use this method on DOM Element objects. + + @private + @method guidFor + @for Ember + @param {Object} obj any object, string, number, Element, or primitive + @return {String} the unique guid for this instance. + */ + function guidFor(obj) { + + // special cases where we don't want to add a key to object + if (obj === undefined) return "(undefined)"; + if (obj === null) return "(null)"; + + var ret; + var type = typeof obj; + + // Don't allow prototype changes to String etc. to change the guidFor + switch(type) { + case 'number': + ret = numberCache[obj]; + if (!ret) ret = numberCache[obj] = 'nu'+obj; + return ret; + + case 'string': + ret = stringCache[obj]; + if (!ret) ret = stringCache[obj] = 'st' + uuid(); + return ret; + + case 'boolean': + return obj ? '(true)' : '(false)'; + + default: + if (obj[GUID_KEY]) return obj[GUID_KEY]; + if (obj === Object) return '(Object)'; + if (obj === Array) return '(Array)'; + ret = GUID_PREFIX + uuid(); + + if (obj[GUID_KEY] === null) { + obj[GUID_KEY] = ret; + } else { + GUID_DESC.value = ret; + o_defineProperty(obj, GUID_KEY, GUID_DESC); + } + return ret; + } + } + + __exports__.guidFor = guidFor;// .......................................................... + // META + // + + var META_DESC = { + writable: true, + configurable: false, + enumerable: false, + value: null + }; + + function Meta(obj) { + this.descs = {}; + this.watching = {}; + this.cache = {}; + this.cacheMeta = {}; + this.source = obj; + } + + Meta.prototype = { + descs: null, + deps: null, + watching: null, + listeners: null, + cache: null, + cacheMeta: null, + source: null, + mixins: null, + bindings: null, + chains: null, + chainWatchers: null, + values: null, + proto: null + }; + + if (!canDefineNonEnumerableProperties) { + // on platforms that don't support enumerable false + // make meta fail jQuery.isPlainObject() to hide from + // jQuery.extend() by having a property that fails + // hasOwnProperty check. + Meta.prototype.__preventPlainObject__ = true; + + // Without non-enumerable properties, meta objects will be output in JSON + // unless explicitly suppressed + Meta.prototype.toJSON = function () { }; + } + + // Placeholder for non-writable metas. + var EMPTY_META = new Meta(null); + + + if (hasPropertyAccessors) { + EMPTY_META.values = {}; + } + + + /** + Retrieves the meta hash for an object. If `writable` is true ensures the + hash is writable for this object as well. + + The meta object contains information about computed property descriptors as + well as any watched properties and other information. You generally will + not access this information directly but instead work with higher level + methods that manipulate this hash indirectly. + + @method meta + @for Ember + @private + + @param {Object} obj The object to retrieve meta for + @param {Boolean} [writable=true] Pass `false` if you do not intend to modify + the meta hash, allowing the method to avoid making an unnecessary copy. + @return {Object} the meta hash for an object + */ + function meta(obj, writable) { + + var ret = obj['__ember_meta__']; + if (writable===false) return ret || EMPTY_META; + + if (!ret) { + if (canDefineNonEnumerableProperties) o_defineProperty(obj, '__ember_meta__', META_DESC); + + ret = new Meta(obj); + + + if (hasPropertyAccessors) { + ret.values = {}; + } + + + obj['__ember_meta__'] = ret; + + // make sure we don't accidentally try to create constructor like desc + ret.descs.constructor = null; + + } else if (ret.source !== obj) { + if (canDefineNonEnumerableProperties) o_defineProperty(obj, '__ember_meta__', META_DESC); + + ret = o_create(ret); + ret.descs = o_create(ret.descs); + ret.watching = o_create(ret.watching); + ret.cache = {}; + ret.cacheMeta = {}; + ret.source = obj; + + + if (hasPropertyAccessors) { + ret.values = o_create(ret.values); + } + + + obj['__ember_meta__'] = ret; + } + return ret; + } + + function getMeta(obj, property) { + var _meta = meta(obj, false); + return _meta[property]; + } + + __exports__.getMeta = getMeta;function setMeta(obj, property, value) { + var _meta = meta(obj, true); + _meta[property] = value; + return value; + } + + __exports__.setMeta = setMeta;/** + @deprecated + @private + + In order to store defaults for a class, a prototype may need to create + a default meta object, which will be inherited by any objects instantiated + from the class's constructor. + + However, the properties of that meta object are only shallow-cloned, + so if a property is a hash (like the event system's `listeners` hash), + it will by default be shared across all instances of that class. + + This method allows extensions to deeply clone a series of nested hashes or + other complex objects. For instance, the event system might pass + `['listeners', 'foo:change', 'ember157']` to `prepareMetaPath`, which will + walk down the keys provided. + + For each key, if the key does not exist, it is created. If it already + exists and it was inherited from its constructor, the constructor's + key is cloned. + + You can also pass false for `writable`, which will simply return + undefined if `prepareMetaPath` discovers any part of the path that + shared or undefined. + + @method metaPath + @for Ember + @param {Object} obj The object whose meta we are examining + @param {Array} path An array of keys to walk down + @param {Boolean} writable whether or not to create a new meta + (or meta property) if one does not already exist or if it's + shared with its constructor + */ + function metaPath(obj, path, writable) { + Ember.deprecate("Ember.metaPath is deprecated and will be removed from future releases."); + var _meta = meta(obj, writable); + var keyName, value; + + for (var i=0, l=path.length; i 1) { + watching[keyName]--; + } + } + + __exports__.unwatchKey = unwatchKey; + }); +enifed("ember-metal/watch_path", + ["ember-metal/utils","ember-metal/chains","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var meta = __dependency1__.meta; + var typeOf = __dependency1__.typeOf; + var ChainNode = __dependency2__.ChainNode; + + var metaFor = meta; + + // get the chains for the current object. If the current object has + // chains inherited from the proto they will be cloned and reconfigured for + // the current object. + function chainsFor(obj, meta) { + var m = meta || metaFor(obj); + var ret = m.chains; + if (!ret) { + ret = m.chains = new ChainNode(null, null, obj); + } else if (ret.value() !== obj) { + ret = m.chains = ret.copy(obj); + } + return ret; + } + + function watchPath(obj, keyPath, meta) { + // can't watch length on Array - it is special... + if (keyPath === 'length' && typeOf(obj) === 'array') { return; } + + var m = meta || metaFor(obj); + var watching = m.watching; + + if (!watching[keyPath]) { // activate watching first time + watching[keyPath] = 1; + chainsFor(obj, m).add(keyPath); + } else { + watching[keyPath] = (watching[keyPath] || 0) + 1; + } + } + + __exports__.watchPath = watchPath;function unwatchPath(obj, keyPath, meta) { + var m = meta || metaFor(obj); + var watching = m.watching; + + if (watching[keyPath] === 1) { + watching[keyPath] = 0; + chainsFor(obj, m).remove(keyPath); + } else if (watching[keyPath] > 1) { + watching[keyPath]--; + } + } + + __exports__.unwatchPath = unwatchPath; + }); +enifed("ember-metal/watching", + ["ember-metal/utils","ember-metal/chains","ember-metal/watch_key","ember-metal/watch_path","ember-metal/path_cache","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + /** + @module ember-metal + */ + + var meta = __dependency1__.meta; + var GUID_KEY = __dependency1__.GUID_KEY; + var typeOf = __dependency1__.typeOf; + var generateGuid = __dependency1__.generateGuid; + var removeChainWatcher = __dependency2__.removeChainWatcher; + var flushPendingChains = __dependency2__.flushPendingChains; + var watchKey = __dependency3__.watchKey; + var unwatchKey = __dependency3__.unwatchKey; + var watchPath = __dependency4__.watchPath; + var unwatchPath = __dependency4__.unwatchPath; + + var metaFor = meta; // utils.js + var isPath = __dependency5__.isPath; + + /** + Starts watching a property on an object. Whenever the property changes, + invokes `Ember.propertyWillChange` and `Ember.propertyDidChange`. This is the + primitive used by observers and dependent keys; usually you will never call + this method directly but instead use higher level methods like + `Ember.addObserver()` + + @private + @method watch + @for Ember + @param obj + @param {String} keyName + */ + function watch(obj, _keyPath, m) { + // can't watch length on Array - it is special... + if (_keyPath === 'length' && typeOf(obj) === 'array') { return; } + + if (!isPath(_keyPath)) { + watchKey(obj, _keyPath, m); + } else { + watchPath(obj, _keyPath, m); + } + } + + __exports__.watch = watch; + + function isWatching(obj, key) { + var meta = obj['__ember_meta__']; + return (meta && meta.watching[key]) > 0; + } + + __exports__.isWatching = isWatching;watch.flushPending = flushPendingChains; + + function unwatch(obj, _keyPath, m) { + // can't watch length on Array - it is special... + if (_keyPath === 'length' && typeOf(obj) === 'array') { return; } + + if (!isPath(_keyPath)) { + unwatchKey(obj, _keyPath, m); + } else { + unwatchPath(obj, _keyPath, m); + } + } + + __exports__.unwatch = unwatch;/** + Call on an object when you first beget it from another object. This will + setup any chained watchers on the object instance as needed. This method is + safe to call multiple times. + + @private + @method rewatch + @for Ember + @param obj + */ + function rewatch(obj) { + var m = obj['__ember_meta__'], chains = m && m.chains; + + // make sure the object has its own guid. + if (GUID_KEY in obj && !obj.hasOwnProperty(GUID_KEY)) { + generateGuid(obj); + } + + // make sure any chained watchers update. + if (chains && chains.value() !== obj) { + m.chains = chains.copy(obj); + } + } + + __exports__.rewatch = rewatch;var NODE_STACK = []; + + /** + Tears down the meta on an object so that it can be garbage collected. + Multiple calls will have no effect. + + @method destroy + @for Ember + @param {Object} obj the object to destroy + @return {void} + */ + function destroy(obj) { + var meta = obj['__ember_meta__'], node, nodes, key, nodeObject; + if (meta) { + obj['__ember_meta__'] = null; + // remove chainWatchers to remove circular references that would prevent GC + node = meta.chains; + if (node) { + NODE_STACK.push(node); + // process tree + while (NODE_STACK.length > 0) { + node = NODE_STACK.pop(); + // push children + nodes = node._chains; + if (nodes) { + for (key in nodes) { + if (nodes.hasOwnProperty(key)) { + NODE_STACK.push(nodes[key]); + } + } + } + // remove chainWatcher in node object + if (node._watching) { + nodeObject = node._object; + if (nodeObject) { + removeChainWatcher(nodeObject, node._key, node); + } + } + } + } + } + } + + __exports__.destroy = destroy; + }); +enifed("ember-routing-handlebars", + ["ember-metal/core","ember-handlebars","ember-routing/system/router","ember-routing-handlebars/helpers/shared","ember-routing-handlebars/helpers/link_to","ember-routing-handlebars/helpers/outlet","ember-routing-handlebars/helpers/render","ember-routing-handlebars/helpers/action","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + /** + Ember Routing Handlebars + + @module ember + @submodule ember-routing-handlebars + @requires ember-views + */ + + var Ember = __dependency1__["default"]; + var EmberHandlebars = __dependency2__["default"]; + var Router = __dependency3__["default"]; + + var resolvePaths = __dependency4__.resolvePaths; + var resolveParams = __dependency4__.resolveParams; + + var deprecatedLinkToHelper = __dependency5__.deprecatedLinkToHelper; + var linkToHelper = __dependency5__.linkToHelper; + var LinkView = __dependency5__.LinkView; + var queryParamsHelper = __dependency5__.queryParamsHelper; + + var outletHelper = __dependency6__.outletHelper; + var OutletView = __dependency6__.OutletView; + + var renderHelper = __dependency7__["default"]; + + var ActionHelper = __dependency8__.ActionHelper; + var actionHelper = __dependency8__.actionHelper; + + Router.resolveParams = resolveParams; + Router.resolvePaths = resolvePaths; + + Ember.LinkView = LinkView; + EmberHandlebars.ActionHelper = ActionHelper; + EmberHandlebars.OutletView = OutletView; + + EmberHandlebars.registerHelper('render', renderHelper); + EmberHandlebars.registerHelper('action', actionHelper); + EmberHandlebars.registerHelper('outlet', outletHelper); + EmberHandlebars.registerHelper('link-to', linkToHelper); + EmberHandlebars.registerHelper('linkTo', deprecatedLinkToHelper); + EmberHandlebars.registerHelper('query-params', queryParamsHelper); + + __exports__["default"] = Ember; + }); +enifed("ember-routing-handlebars/helpers/action", + ["ember-metal/core","ember-metal/property_get","ember-metal/array","ember-metal/utils","ember-metal/run_loop","ember-views/system/utils","ember-views/system/action_manager","ember-routing/system/router","ember-handlebars","ember-handlebars/ext","ember-handlebars/helpers/view","ember-routing-handlebars/helpers/shared","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Handlebars, uuid, FEATURES, assert, deprecate + var get = __dependency2__.get; + var forEach = __dependency3__.forEach; + var uuid = __dependency4__.uuid; + var run = __dependency5__["default"]; + + var isSimpleClick = __dependency6__.isSimpleClick; + var ActionManager = __dependency7__["default"]; + var EmberRouter = __dependency8__["default"]; + + var EmberHandlebars = __dependency9__["default"]; + var handlebarsGet = __dependency10__.handlebarsGet; + var viewHelper = __dependency11__.viewHelper; + var resolveParams = __dependency12__.resolveParams; + var resolvePath = __dependency12__.resolvePath; + + /** + @module ember + @submodule ember-routing + */ + + var SafeString = EmberHandlebars.SafeString; + var a_slice = Array.prototype.slice; + + function args(options, actionName) { + var ret = []; + if (actionName) { ret.push(actionName); } + + var types = options.options.types.slice(1); + var data = options.options.data; + + return ret.concat(resolveParams(options.context, options.params, { types: types, data: data })); + } + + var ActionHelper = {}; + + // registeredActions is re-exported for compatibility with older plugins + // that were using this undocumented API. + ActionHelper.registeredActions = ActionManager.registeredActions; + + __exports__.ActionHelper = ActionHelper; + + var keys = ["alt", "shift", "meta", "ctrl"]; + + var POINTER_EVENT_TYPE_REGEX = /^click|mouse|touch/; + + var isAllowedEvent = function(event, allowedKeys) { + if (typeof allowedKeys === "undefined") { + if (POINTER_EVENT_TYPE_REGEX.test(event.type)) { + return isSimpleClick(event); + } else { + allowedKeys = ''; + } + } + + if (allowedKeys.indexOf("any") >= 0) { + return true; + } + + var allowed = true; + + forEach.call(keys, function(key) { + if (event[key + "Key"] && allowedKeys.indexOf(key) === -1) { + allowed = false; + } + }); + + return allowed; + }; + + function isKeyEvent(eventName) { + return ['keyUp', 'keyPress', 'keyDown'].indexOf(eventName) !== -1; + } + + function ignoreKeyEvent(eventName, event, keyCode) { + var any = 'any'; + keyCode = keyCode || any; + return isKeyEvent(eventName) && keyCode !== any && keyCode !== event.which.toString(); + } + + ActionHelper.registerAction = function(actionNameOrPath, options, allowedKeys) { + var actionId = uuid(); + + ActionManager.registeredActions[actionId] = { + eventName: options.eventName, + handler: function handleRegisteredAction(event) { + if (!isAllowedEvent(event, allowedKeys)) { return true; } + + if (options.preventDefault !== false) { + event.preventDefault(); + } + + if (options.bubbles === false) { + event.stopPropagation(); + } + + var target = options.target; + var parameters = options.parameters; + var eventName = options.eventName; + var actionName; + + + if (target.target) { + target = handlebarsGet(target.root, target.target, target.options); + } else { + target = target.root; + } + + if (options.boundProperty) { + actionName = resolveParams(parameters.context, [actionNameOrPath], { types: ['ID'], data: parameters.options.data })[0]; + + if (typeof actionName === 'undefined' || typeof actionName === 'function') { + Ember.deprecate("You specified a quoteless path to the {{action}} helper '" + actionNameOrPath + "' which did not resolve to an actionName. Perhaps you meant to use a quoted actionName? (e.g. {{action '" + actionNameOrPath + "'}})."); + actionName = actionNameOrPath; + } + } + + if (!actionName) { + actionName = actionNameOrPath; + } + + run(function runRegisteredAction() { + if (target.send) { + target.send.apply(target, args(parameters, actionName)); + } else { + Ember.assert("The action '" + actionName + "' did not exist on " + target, typeof target[actionName] === 'function'); + target[actionName].apply(target, args(parameters)); + } + }); + } + }; + + options.view.on('willClearRender', function() { + delete ActionManager.registeredActions[actionId]; + }); + + return actionId; + }; + + /** + + The `{{action}}` helper provides a useful shortcut for registering an HTML + element within a template for a single DOM event and forwarding that + interaction to the template's controller or specified `target` option. + + If the controller does not implement the specified action, the event is sent + to the current route, and it bubbles up the route hierarchy from there. + + For more advanced event handling see [Ember.Component](/api/classes/Ember.Component.html) + + + ### Use + Given the following application Handlebars template on the page + + ```handlebars +
    + click me +
    + ``` + + And application code + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + actions: { + anActionName: function() { + } + } + }); + ``` + + Will result in the following rendered HTML + + ```html +
    +
    + click me +
    +
    + ``` + + Clicking "click me" will trigger the `anActionName` action of the + `App.ApplicationController`. In this case, no additional parameters will be passed. + + If you provide additional parameters to the helper: + + ```handlebars + + ``` + + Those parameters will be passed along as arguments to the JavaScript + function implementing the action. + + ### Event Propagation + + Events triggered through the action helper will automatically have + `.preventDefault()` called on them. You do not need to do so in your event + handlers. If you need to allow event propagation (to handle file inputs for + example) you can supply the `preventDefault=false` option to the `{{action}}` helper: + + ```handlebars +
    + + +
    + ``` + + To disable bubbling, pass `bubbles=false` to the helper: + + ```handlebars + + ``` + + If you need the default handler to trigger you should either register your + own event handler, or use event methods on your view class. See [Ember.View](/api/classes/Ember.View.html) + 'Responding to Browser Events' for more information. + + ### Specifying DOM event type + + By default the `{{action}}` helper registers for DOM `click` events. You can + supply an `on` option to the helper to specify a different DOM event name: + + ```handlebars +
    + click me +
    + ``` + + See `Ember.View` 'Responding to Browser Events' for a list of + acceptable DOM event names. + + ### Specifying whitelisted modifier keys + + By default the `{{action}}` helper will ignore click event with pressed modifier + keys. You can supply an `allowedKeys` option to specify which keys should not be ignored. + + ```handlebars +
    + click me +
    + ``` + + This way the `{{action}}` will fire when clicking with the alt key pressed down. + + Alternatively, supply "any" to the `allowedKeys` option to accept any combination of modifier keys. + + ```handlebars +
    + click me with any key pressed +
    + ``` + + ### Specifying a Target + + There are several possible target objects for `{{action}}` helpers: + + In a typical Ember application, where templates are managed through use of the + `{{outlet}}` helper, actions will bubble to the current controller, then + to the current route, and then up the route hierarchy. + + Alternatively, a `target` option can be provided to the helper to change + which object will receive the method call. This option must be a path + to an object, accessible in the current context: + + ```handlebars + {{! the application template }} +
    + click me +
    + ``` + + ```javascript + App.ApplicationView = Ember.View.extend({ + actions: { + anActionName: function(){} + } + }); + + ``` + + ### Additional Parameters + + You may specify additional parameters to the `{{action}}` helper. These + parameters are passed along as the arguments to the JavaScript function + implementing the action. + + ```handlebars + {{#each person in people}} +
    + click me +
    + {{/each}} + ``` + + Clicking "click me" will trigger the `edit` method on the current controller + with the value of `person` as a parameter. + + @method action + @for Ember.Handlebars.helpers + @param {String} actionName + @param {Object} [context]* + @param {Hash} options + */ + function actionHelper(actionName) { + var options = arguments[arguments.length - 1]; + var contexts = a_slice.call(arguments, 1, -1); + var hash = options.hash; + var controller = options.data.keywords.controller; + + // create a hash to pass along to registerAction + var action = { + eventName: hash.on || "click", + parameters: { + context: this, + options: options, + params: contexts + }, + view: options.data.view, + bubbles: hash.bubbles, + preventDefault: hash.preventDefault, + target: { options: options }, + withKeyCode: hash.withKeyCode, + boundProperty: options.types[0] === "ID" + }; + + if (hash.target) { + action.target.root = this; + action.target.target = hash.target; + } else if (controller) { + action.target.root = controller; + } + + var actionId = ActionHelper.registerAction(actionName, action, hash.allowedKeys); + return new SafeString('data-ember-action="' + actionId + '"'); + } + + __exports__.actionHelper = actionHelper; + }); +enifed("ember-routing-handlebars/helpers/link_to", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/merge","ember-metal/run_loop","ember-metal/computed","ember-runtime/system/lazy_load","ember-runtime/system/string","ember-runtime/system/object","ember-metal/keys","ember-views/system/utils","ember-views/views/component","ember-handlebars","ember-handlebars/helpers/view","ember-routing/system/router","ember-routing-handlebars/helpers/shared","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES, Logger, Handlebars, warn, assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var merge = __dependency4__["default"]; + var run = __dependency5__["default"]; + var computed = __dependency6__.computed; + + var onLoad = __dependency7__.onLoad; + var fmt = __dependency8__.fmt; + var EmberObject = __dependency9__["default"]; + var keys = __dependency10__["default"]; + var isSimpleClick = __dependency11__.isSimpleClick; + var EmberComponent = __dependency12__["default"]; + var EmberHandlebars = __dependency13__["default"]; + var viewHelper = __dependency14__.viewHelper; + var EmberRouter = __dependency15__["default"]; + var resolveParams = __dependency16__.resolveParams; + var resolvePaths = __dependency16__.resolvePaths; + var routeArgs = __dependency16__.routeArgs; + + /** + @module ember + @submodule ember-routing + */ + + var slice = [].slice; + + requireModule('ember-handlebars'); + + var numberOfContextsAcceptedByHandler = function(handler, handlerInfos) { + var req = 0; + for (var i = 0, l = handlerInfos.length; i < l; i++) { + req = req + handlerInfos[i].names.length; + if (handlerInfos[i].handler === handler) + break; + } + + return req; + }; + + var QueryParams = EmberObject.extend({ + values: null + }); + + function getResolvedPaths(options) { + + var types = options.options.types; + var data = options.options.data; + + return resolvePaths(options.context, options.params, { types: types, data: data }); + } + + /** + `Ember.LinkView` renders an element whose `click` event triggers a + transition of the application's instance of `Ember.Router` to + a supplied route by name. + + Instances of `LinkView` will most likely be created through + the `link-to` Handlebars helper, but properties of this class + can be overridden to customize application-wide behavior. + + @class LinkView + @namespace Ember + @extends Ember.View + @see {Handlebars.helpers.link-to} + **/ + var LinkView = Ember.LinkView = EmberComponent.extend({ + tagName: 'a', + + /** + @deprecated Use current-when instead. + @property currentWhen + */ + currentWhen: null, + + /** + Used to determine when this LinkView is active. + + @property currentWhen + */ + 'current-when': null, + + /** + Sets the `title` attribute of the `LinkView`'s HTML element. + + @property title + @default null + **/ + title: null, + + /** + Sets the `rel` attribute of the `LinkView`'s HTML element. + + @property rel + @default null + **/ + rel: null, + + /** + The CSS class to apply to `LinkView`'s element when its `active` + property is `true`. + + @property activeClass + @type String + @default active + **/ + activeClass: 'active', + + /** + The CSS class to apply to `LinkView`'s element when its `loading` + property is `true`. + + @property loadingClass + @type String + @default loading + **/ + loadingClass: 'loading', + + /** + The CSS class to apply to a `LinkView`'s element when its `disabled` + property is `true`. + + @property disabledClass + @type String + @default disabled + **/ + disabledClass: 'disabled', + _isDisabled: false, + + /** + Determines whether the `LinkView` will trigger routing via + the `replaceWith` routing strategy. + + @property replace + @type Boolean + @default false + **/ + replace: false, + + /** + By default the `{{link-to}}` helper will bind to the `href` and + `title` attributes. It's discourage that you override these defaults, + however you can push onto the array if needed. + + @property attributeBindings + @type Array | String + @default ['href', 'title', 'rel'] + **/ + attributeBindings: ['href', 'title', 'rel', 'tabindex'], + + /** + By default the `{{link-to}}` helper will bind to the `active`, `loading`, and + `disabled` classes. It is discouraged to override these directly. + + @property classNameBindings + @type Array + @default ['active', 'loading', 'disabled'] + **/ + classNameBindings: ['active', 'loading', 'disabled'], + + /** + By default the `{{link-to}}` helper responds to the `click` event. You + can override this globally by setting this property to your custom + event name. + + This is particularly useful on mobile when one wants to avoid the 300ms + click delay using some sort of custom `tap` event. + + @property eventName + @type String + @default click + */ + eventName: 'click', + + // this is doc'ed here so it shows up in the events + // section of the API documentation, which is where + // people will likely go looking for it. + /** + Triggers the `LinkView`'s routing behavior. If + `eventName` is changed to a value other than `click` + the routing behavior will trigger on that custom event + instead. + + @event click + **/ + + /** + An overridable method called when LinkView objects are instantiated. + + Example: + + ```javascript + App.MyLinkView = Ember.LinkView.extend({ + init: function() { + this._super(); + Ember.Logger.log('Event is ' + this.get('eventName')); + } + }); + ``` + + NOTE: If you do override `init` for a framework class like `Ember.View` or + `Ember.ArrayController`, be sure to call `this._super()` in your + `init` declaration! If you don't, Ember may not have an opportunity to + do important setup work, and you'll see strange behavior in your + application. + + @method init + */ + init: function() { + this._super.apply(this, arguments); + + Ember.deprecate('Using currentWhen with {{link-to}} is deprecated in favor of `current-when`.', !this.currentWhen); + + // Map desired event name to invoke function + var eventName = get(this, 'eventName'); + this.on(eventName, this, this._invoke); + }, + + /** + This method is invoked by observers installed during `init` that fire + whenever the params change + + @private + @method _paramsChanged + @since 1.3.0 + */ + _paramsChanged: function() { + this.notifyPropertyChange('resolvedParams'); + }, + + /** + This is called to setup observers that will trigger a rerender. + + @private + @method _setupPathObservers + @since 1.3.0 + **/ + _setupPathObservers: function(){ + var helperParameters = this.parameters; + var linkTextPath = helperParameters.options.linkTextPath; + var paths = getResolvedPaths(helperParameters); + var length = paths.length; + var path, i, normalizedPath; + + if (linkTextPath) { + normalizedPath = getNormalizedPath(linkTextPath, helperParameters); + this.registerObserver(normalizedPath.root, normalizedPath.path, this, this.rerender); + } + + for(i=0; i < length; i++) { + path = paths[i]; + if (null === path) { + // A literal value was provided, not a path, so nothing to observe. + continue; + } + + normalizedPath = getNormalizedPath(path, helperParameters); + this.registerObserver(normalizedPath.root, normalizedPath.path, this, this._paramsChanged); + } + + var queryParamsObject = this.queryParamsObject; + if (queryParamsObject) { + var values = queryParamsObject.values; + + // Install observers for all of the hash options + // provided in the (query-params) subexpression. + for (var k in values) { + if (!values.hasOwnProperty(k)) { continue; } + + if (queryParamsObject.types[k] === 'ID') { + normalizedPath = getNormalizedPath(values[k], helperParameters); + this.registerObserver(normalizedPath.root, normalizedPath.path, this, this._paramsChanged); + } + } + } + }, + + afterRender: function(){ + this._super.apply(this, arguments); + this._setupPathObservers(); + }, + + /** + + Accessed as a classname binding to apply the `LinkView`'s `disabledClass` + CSS `class` to the element when the link is disabled. + + When `true` interactions with the element will not trigger route changes. + @property disabled + */ + disabled: computed(function computeLinkViewDisabled(key, value) { + if (value !== undefined) { this.set('_isDisabled', value); } + + return value ? get(this, 'disabledClass') : false; + }), + + /** + Accessed as a classname binding to apply the `LinkView`'s `activeClass` + CSS `class` to the element when the link is active. + + A `LinkView` is considered active when its `currentWhen` property is `true` + or the application's current route is the route the `LinkView` would trigger + transitions into. + + The `currentWhen` property can match against multiple routes by separating + route names using the ` ` (space) character. + + @property active + **/ + active: computed('loadedParams', function computeLinkViewActive() { + if (get(this, 'loading')) { return false; } + + var router = get(this, 'router'); + var loadedParams = get(this, 'loadedParams'); + var contexts = loadedParams.models; + var currentWhen = this['current-when'] || this.currentWhen; + var isCurrentWhenSpecified = Boolean(currentWhen); + currentWhen = currentWhen || loadedParams.targetRouteName; + + function isActiveForRoute(routeName) { + var handlers = router.router.recognizer.handlersFor(routeName); + var leafName = handlers[handlers.length-1].handler; + var maximumContexts = numberOfContextsAcceptedByHandler(routeName, handlers); + + // NOTE: any ugliness in the calculation of activeness is largely + // due to the fact that we support automatic normalizing of + // `resource` -> `resource.index`, even though there might be + // dynamic segments / query params defined on `resource.index` + // which complicates (and makes somewhat ambiguous) the calculation + // of activeness for links that link to `resource` instead of + // directly to `resource.index`. + + // if we don't have enough contexts revert back to full route name + // this is because the leaf route will use one of the contexts + if (contexts.length > maximumContexts) { + routeName = leafName; + } + + var args = routeArgs(routeName, contexts, null); + var isActive = router.isActive.apply(router, args); + if (!isActive) { return false; } + + var emptyQueryParams = Ember.isEmpty(Ember.keys(loadedParams.queryParams)); + + if (!isCurrentWhenSpecified && !emptyQueryParams && isActive) { + var visibleQueryParams = {}; + merge(visibleQueryParams, loadedParams.queryParams); + router._prepareQueryParams(loadedParams.targetRouteName, loadedParams.models, visibleQueryParams); + isActive = shallowEqual(visibleQueryParams, router.router.state.queryParams); + } + + return isActive; + } + + + currentWhen = currentWhen.split(' '); + for (var i = 0, len = currentWhen.length; i < len; i++) { + if (isActiveForRoute(currentWhen[i])) { + return get(this, 'activeClass'); + } + } + }), + + /** + Accessed as a classname binding to apply the `LinkView`'s `loadingClass` + CSS `class` to the element when the link is loading. + + A `LinkView` is considered loading when it has at least one + parameter whose value is currently null or undefined. During + this time, clicking the link will perform no transition and + emit a warning that the link is still in a loading state. + + @property loading + **/ + loading: computed('loadedParams', function computeLinkViewLoading() { + if (!get(this, 'loadedParams')) { return get(this, 'loadingClass'); } + }), + + /** + Returns the application's main router from the container. + + @private + @property router + **/ + router: computed(function() { + var controller = get(this, 'controller'); + if (controller && controller.container) { + return controller.container.lookup('router:main'); + } + }), + + /** + Event handler that invokes the link, activating the associated route. + + @private + @method _invoke + @param {Event} event + */ + _invoke: function(event) { + if (!isSimpleClick(event)) { return true; } + + if (this.preventDefault !== false) { + + var targetAttribute = get(this, 'target'); + if (!targetAttribute || targetAttribute === '_self') { + event.preventDefault(); + } + } + + if (this.bubbles === false) { event.stopPropagation(); } + + if (get(this, '_isDisabled')) { return false; } + + if (get(this, 'loading')) { + Ember.Logger.warn("This link-to is in an inactive loading state because at least one of its parameters presently has a null/undefined value, or the provided route name is invalid."); + return false; + } + + + var targetAttribute2 = get(this, 'target'); + if (targetAttribute2 && targetAttribute2 !== '_self') { + return false; + } + + + var router = get(this, 'router'); + var loadedParams = get(this, 'loadedParams'); + + var transition = router._doTransition(loadedParams.targetRouteName, loadedParams.models, loadedParams.queryParams); + if (get(this, 'replace')) { + transition.method('replace'); + } + + // Schedule eager URL update, but after we've given the transition + // a chance to synchronously redirect. + // We need to always generate the URL instead of using the href because + // the href will include any rootURL set, but the router expects a URL + // without it! Note that we don't use the first level router because it + // calls location.formatURL(), which also would add the rootURL! + var args = routeArgs(loadedParams.targetRouteName, loadedParams.models, transition.state.queryParams); + var url = router.router.generate.apply(router.router, args); + + run.scheduleOnce('routerTransitions', this, this._eagerUpdateUrl, transition, url); + }, + + /** + @private + @method _eagerUpdateUrl + @param transition + @param href + */ + _eagerUpdateUrl: function(transition, href) { + if (!transition.isActive || !transition.urlMethod) { + // transition was aborted, already ran to completion, + // or it has a null url-updated method. + return; + } + + if (href.indexOf('#') === 0) { + href = href.slice(1); + } + + // Re-use the routerjs hooks set up by the Ember router. + var routerjs = get(this, 'router.router'); + if (transition.urlMethod === 'update') { + routerjs.updateURL(href); + } else if (transition.urlMethod === 'replace') { + routerjs.replaceURL(href); + } + + // Prevent later update url refire. + transition.method(null); + }, + + /** + Computed property that returns an array of the + resolved parameters passed to the `link-to` helper, + e.g.: + + ```hbs + {{link-to a b '123' c}} + ``` + + will generate a `resolvedParams` of: + + ```js + [aObject, bObject, '123', cObject] + ``` + + @private + @property + @return {Array} + */ + resolvedParams: computed('router.url', function() { + var parameters = this.parameters; + var options = parameters.options; + var types = options.types; + var data = options.data; + var targetRouteName, models; + var onlyQueryParamsSupplied = (parameters.params.length === 0); + + if (onlyQueryParamsSupplied) { + var appController = this.container.lookup('controller:application'); + targetRouteName = get(appController, 'currentRouteName'); + models = []; + } else { + models = resolveParams(parameters.context, parameters.params, { types: types, data: data }); + targetRouteName = models.shift(); + } + + var suppliedQueryParams = getResolvedQueryParams(this, targetRouteName); + + return { + targetRouteName: targetRouteName, + models: models, + queryParams: suppliedQueryParams + }; + }), + + /** + Computed property that returns the current route name, + dynamic segments, and query params. Returns falsy if + for null/undefined params to indicate that the link view + is still in a loading state. + + @private + @property + @return {Array} An array with the route name and any dynamic segments + **/ + loadedParams: computed('resolvedParams', function computeLinkViewRouteArgs() { + var router = get(this, 'router'); + if (!router) { return; } + + var resolvedParams = get(this, 'resolvedParams'); + var namedRoute = resolvedParams.targetRouteName; + + if (!namedRoute) { return; } + + Ember.assert(fmt("The attempt to link-to route '%@' failed. " + + "The router did not find '%@' in its possible routes: '%@'", + [namedRoute, namedRoute, keys(router.router.recognizer.names).join("', '")]), + router.hasRoute(namedRoute)); + + if (!paramsAreLoaded(resolvedParams.models)) { return; } + + return resolvedParams; + }), + + queryParamsObject: null, + + /** + Sets the element's `href` attribute to the url for + the `LinkView`'s targeted route. + + If the `LinkView`'s `tagName` is changed to a value other + than `a`, this property will be ignored. + + @property href + **/ + href: computed('loadedParams', function computeLinkViewHref() { + if (get(this, 'tagName') !== 'a') { return; } + + var router = get(this, 'router'); + var loadedParams = get(this, 'loadedParams'); + + if (!loadedParams) { + return get(this, 'loadingHref'); + } + + var visibleQueryParams = {}; + merge(visibleQueryParams, loadedParams.queryParams); + router._prepareQueryParams(loadedParams.targetRouteName, loadedParams.models, visibleQueryParams); + + var args = routeArgs(loadedParams.targetRouteName, loadedParams.models, visibleQueryParams); + var result = router.generate.apply(router, args); + return result; + }), + + /** + The default href value to use while a link-to is loading. + Only applies when tagName is 'a' + + @property loadingHref + @type String + @default # + */ + loadingHref: '#' + }); + + LinkView.toString = function() { return "LinkView"; }; + + + LinkView.reopen({ + attributeBindings: ['target'], + + /** + Sets the `target` attribute of the `LinkView`'s anchor element. + + @property target + @default null + **/ + target: null + }); + + + /** + The `{{link-to}}` helper renders a link to the supplied + `routeName` passing an optionally supplied model to the + route as its `model` context of the route. The block + for `{{link-to}}` becomes the innerHTML of the rendered + element: + + ```handlebars + {{#link-to 'photoGallery'}} + Great Hamster Photos + {{/link-to}} + ``` + + ```html + + Great Hamster Photos + + ``` + + ### Supplying a tagName + By default `{{link-to}}` renders an `` element. This can + be overridden for a single use of `{{link-to}}` by supplying + a `tagName` option: + + ```handlebars + {{#link-to 'photoGallery' tagName="li"}} + Great Hamster Photos + {{/link-to}} + ``` + + ```html +
  • + Great Hamster Photos +
  • + ``` + + To override this option for your entire application, see + "Overriding Application-wide Defaults". + + ### Disabling the `link-to` helper + By default `{{link-to}}` is enabled. + any passed value to `disabled` helper property will disable the `link-to` helper. + + static use: the `disabled` option: + + ```handlebars + {{#link-to 'photoGallery' disabled=true}} + Great Hamster Photos + {{/link-to}} + ``` + + dynamic use: the `disabledWhen` option: + + ```handlebars + {{#link-to 'photoGallery' disabledWhen=controller.someProperty}} + Great Hamster Photos + {{/link-to}} + ``` + + any passed value to `disabled` will disable it except `undefined`. + to ensure that only `true` disable the `link-to` helper you can + override the global behaviour of `Ember.LinkView`. + + ```javascript + Ember.LinkView.reopen({ + disabled: Ember.computed(function(key, value) { + if (value !== undefined) { + this.set('_isDisabled', value === true); + } + return value === true ? get(this, 'disabledClass') : false; + }) + }); + ``` + + see "Overriding Application-wide Defaults" for more. + + ### Handling `href` + `{{link-to}}` will use your application's Router to + fill the element's `href` property with a url that + matches the path to the supplied `routeName` for your + routers's configured `Location` scheme, which defaults + to Ember.HashLocation. + + ### Handling current route + `{{link-to}}` will apply a CSS class name of 'active' + when the application's current route matches + the supplied routeName. For example, if the application's + current route is 'photoGallery.recent' the following + use of `{{link-to}}`: + + ```handlebars + {{#link-to 'photoGallery.recent'}} + Great Hamster Photos from the last week + {{/link-to}} + ``` + + will result in + + ```html +
    + Great Hamster Photos + + ``` + + The CSS class name used for active classes can be customized + for a single use of `{{link-to}}` by passing an `activeClass` + option: + + ```handlebars + {{#link-to 'photoGallery.recent' activeClass="current-url"}} + Great Hamster Photos from the last week + {{/link-to}} + ``` + + ```html + + Great Hamster Photos + + ``` + + To override this option for your entire application, see + "Overriding Application-wide Defaults". + + ### Supplying a model + An optional model argument can be used for routes whose + paths contain dynamic segments. This argument will become + the model context of the linked route: + + ```javascript + App.Router.map(function() { + this.resource("photoGallery", {path: "hamster-photos/:photo_id"}); + }); + ``` + + ```handlebars + {{#link-to 'photoGallery' aPhoto}} + {{aPhoto.title}} + {{/link-to}} + ``` + + ```html + + Tomster + + ``` + + ### Supplying multiple models + For deep-linking to route paths that contain multiple + dynamic segments, multiple model arguments can be used. + As the router transitions through the route path, each + supplied model argument will become the context for the + route with the dynamic segments: + + ```javascript + App.Router.map(function() { + this.resource("photoGallery", {path: "hamster-photos/:photo_id"}, function() { + this.route("comment", {path: "comments/:comment_id"}); + }); + }); + ``` + This argument will become the model context of the linked route: + + ```handlebars + {{#link-to 'photoGallery.comment' aPhoto comment}} + {{comment.body}} + {{/link-to}} + ``` + + ```html + + A+++ would snuggle again. + + ``` + + ### Supplying an explicit dynamic segment value + If you don't have a model object available to pass to `{{link-to}}`, + an optional string or integer argument can be passed for routes whose + paths contain dynamic segments. This argument will become the value + of the dynamic segment: + + ```javascript + App.Router.map(function() { + this.resource("photoGallery", {path: "hamster-photos/:photo_id"}); + }); + ``` + + ```handlebars + {{#link-to 'photoGallery' aPhotoId}} + {{aPhoto.title}} + {{/link-to}} + ``` + + ```html + + Tomster + + ``` + + When transitioning into the linked route, the `model` hook will + be triggered with parameters including this passed identifier. + + ### Allowing Default Action + + By default the `{{link-to}}` helper prevents the default browser action + by calling `preventDefault()` as this sort of action bubbling is normally + handled internally and we do not want to take the browser to a new URL (for + example). + + If you need to override this behavior specify `preventDefault=false` in + your template: + + ```handlebars + {{#link-to 'photoGallery' aPhotoId preventDefault=false}} + {{aPhotoId.title}} + {{/link-to}} + ``` + + ### Overriding attributes + You can override any given property of the Ember.LinkView + that is generated by the `{{link-to}}` helper by passing + key/value pairs, like so: + + ```handlebars + {{#link-to aPhoto tagName='li' title='Following this link will change your life' classNames='pic sweet'}} + Uh-mazing! + {{/link-to}} + ``` + + See [Ember.LinkView](/api/classes/Ember.LinkView.html) for a + complete list of overrideable properties. Be sure to also + check out inherited properties of `LinkView`. + + ### Overriding Application-wide Defaults + ``{{link-to}}`` creates an instance of Ember.LinkView + for rendering. To override options for your entire + application, reopen Ember.LinkView and supply the + desired values: + + ``` javascript + Ember.LinkView.reopen({ + activeClass: "is-active", + tagName: 'li' + }) + ``` + + It is also possible to override the default event in + this manner: + + ``` javascript + Ember.LinkView.reopen({ + eventName: 'customEventName' + }); + ``` + + @method link-to + @for Ember.Handlebars.helpers + @param {String} routeName + @param {Object} [context]* + @param [options] {Object} Handlebars key/value pairs of options, you can override any property of Ember.LinkView + @return {String} HTML string + @see {Ember.LinkView} + */ + function linkToHelper(name) { + var options = slice.call(arguments, -1)[0]; + var params = slice.call(arguments, 0, -1); + var hash = options.hash; + + Ember.assert("You must provide one or more parameters to the link-to helper.", params.length); + + if (params[params.length - 1] instanceof QueryParams) { + hash.queryParamsObject = params.pop(); + } + + hash.disabledBinding = hash.disabledWhen; + + if (!options.fn) { + var linkTitle = params.shift(); + var linkType = options.types.shift(); + var context = this; + if (linkType === 'ID') { + options.linkTextPath = linkTitle; + options.fn = function() { + return EmberHandlebars.getEscaped(context, linkTitle, options); + }; + } else { + options.fn = function() { + return linkTitle; + }; + } + } + + hash.parameters = { + context: this, + options: options, + params: params + }; + + options.helperName = options.helperName || 'link-to'; + + return viewHelper.call(this, LinkView, options); + } + + /** + @method query-params + @for Ember.Handlebars.helpers + @param {Object} hash takes a hash of query parameters + @return {String} HTML string + */ + function queryParamsHelper(options) { + Ember.assert(fmt("The `query-params` helper only accepts hash parameters, e.g. (query-params queryParamPropertyName='%@') as opposed to just (query-params '%@')", [options, options]), arguments.length === 1); + + return QueryParams.create({ + values: options.hash, + types: options.hashTypes + }); + } + + __exports__.queryParamsHelper = queryParamsHelper;/** + See [link-to](/api/classes/Ember.Handlebars.helpers.html#method_link-to) + + @method linkTo + @for Ember.Handlebars.helpers + @deprecated + @param {String} routeName + @param {Object} [context]* + @return {String} HTML string + */ + function deprecatedLinkToHelper() { + Ember.warn("The 'linkTo' view helper is deprecated in favor of 'link-to'"); + return linkToHelper.apply(this, arguments); + } + + function getResolvedQueryParams(linkView, targetRouteName) { + var helperParameters = linkView.parameters; + var queryParamsObject = linkView.queryParamsObject; + var resolvedQueryParams = {}; + + if (!queryParamsObject) { return resolvedQueryParams; } + var rawParams = queryParamsObject.values; + + for (var key in rawParams) { + if (!rawParams.hasOwnProperty(key)) { continue; } + + var value = rawParams[key]; + var type = queryParamsObject.types[key]; + + if (type === 'ID') { + var normalizedPath = getNormalizedPath(value, helperParameters); + value = EmberHandlebars.get(normalizedPath.root, normalizedPath.path, helperParameters.options); + } + resolvedQueryParams[key] = value; + } + return resolvedQueryParams; + } + + function getNormalizedPath(path, helperParameters) { + return EmberHandlebars.normalizePath(helperParameters.context, path, helperParameters.options.data); + } + + function paramsAreLoaded(params) { + for (var i = 0, len = params.length; i < len; ++i) { + var param = params[i]; + if (param === null || typeof param === 'undefined') { + return false; + } + } + return true; + } + + function shallowEqual(a, b) { + var k; + for (k in a) { + if (a.hasOwnProperty(k) && a[k] !== b[k]) { return false; } + } + for (k in b) { + if (b.hasOwnProperty(k) && a[k] !== b[k]) { return false; } + } + return true; + } + + __exports__.LinkView = LinkView; + __exports__.deprecatedLinkToHelper = deprecatedLinkToHelper; + __exports__.linkToHelper = linkToHelper; + }); +enifed("ember-routing-handlebars/helpers/outlet", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/lazy_load","ember-views/views/container_view","ember-handlebars/views/metamorph_view","ember-handlebars/helpers/view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var onLoad = __dependency4__.onLoad; + var ContainerView = __dependency5__["default"]; + var _Metamorph = __dependency6__._Metamorph; + var viewHelper = __dependency7__.viewHelper; + + /** + @module ember + @submodule ember-routing + */ + + /** + @module ember + @submodule ember-routing + */ + + var OutletView = ContainerView.extend(_Metamorph); + __exports__.OutletView = OutletView; + /** + The `outlet` helper is a placeholder that the router will fill in with + the appropriate template based on the current state of the application. + + ``` handlebars + {{outlet}} + ``` + + By default, a template based on Ember's naming conventions will be rendered + into the `outlet` (e.g. `App.PostsRoute` will render the `posts` template). + + You can render a different template by using the `render()` method in the + route's `renderTemplate` hook. The following will render the `favoritePost` + template into the `outlet`. + + ``` javascript + App.PostsRoute = Ember.Route.extend({ + renderTemplate: function() { + this.render('favoritePost'); + } + }); + ``` + + You can create custom named outlets for more control. + + ``` handlebars + {{outlet 'favoritePost'}} + {{outlet 'posts'}} + ``` + + Then you can define what template is rendered into each outlet in your + route. + + + ``` javascript + App.PostsRoute = Ember.Route.extend({ + renderTemplate: function() { + this.render('favoritePost', { outlet: 'favoritePost' }); + this.render('posts', { outlet: 'posts' }); + } + }); + ``` + + You can specify the view that the outlet uses to contain and manage the + templates rendered into it. + + ``` handlebars + {{outlet view='sectionContainer'}} + ``` + + ``` javascript + App.SectionContainer = Ember.ContainerView.extend({ + tagName: 'section', + classNames: ['special'] + }); + ``` + + @method outlet + @for Ember.Handlebars.helpers + @param {String} property the property on the controller + that holds the view for this outlet + @return {String} HTML string + */ + function outletHelper(property, options) { + var outletSource; + var container; + var viewName; + var viewClass; + var viewFullName; + + if (property && property.data && property.data.isRenderData) { + options = property; + property = 'main'; + } + + container = options.data.view.container; + + outletSource = options.data.view; + while (!outletSource.get('template.isTop')) { + outletSource = outletSource.get('_parentView'); + } + + // provide controller override + viewName = options.hash.view; + + if (viewName) { + viewFullName = 'view:' + viewName; + Ember.assert("Using a quoteless view parameter with {{outlet}} is not supported. Please update to quoted usage '{{outlet \"" + viewName + "\"}}.", options.hashTypes.view !== 'ID'); + Ember.assert("The view name you supplied '" + viewName + "' did not resolve to a view.", container.has(viewFullName)); + } + + viewClass = viewName ? container.lookupFactory(viewFullName) : options.hash.viewClass || OutletView; + + options.data.view.set('outletSource', outletSource); + options.hash.currentViewBinding = '_view.outletSource._outlets.' + property; + + options.helperName = options.helperName || 'outlet'; + + return viewHelper.call(this, viewClass, options); + } + + __exports__.outletHelper = outletHelper; + }); +enifed("ember-routing-handlebars/helpers/render", + ["ember-metal/core","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/string","ember-routing/system/generate_controller","ember-handlebars/ext","ember-handlebars/helpers/view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // assert, deprecate + var EmberError = __dependency2__["default"]; + var get = __dependency3__.get; + var set = __dependency4__.set; + var camelize = __dependency5__.camelize; + var generateControllerFactory = __dependency6__.generateControllerFactory; + var generateController = __dependency6__["default"]; + var handlebarsGet = __dependency7__.handlebarsGet; + var ViewHelper = __dependency8__.ViewHelper; + + + /** + @module ember + @submodule ember-routing + */ + + /** + Calling ``{{render}}`` from within a template will insert another + template that matches the provided name. The inserted template will + access its properties on its own controller (rather than the controller + of the parent template). + + If a view class with the same name exists, the view class also will be used. + + Note: A given controller may only be used *once* in your app in this manner. + A singleton instance of the controller will be created for you. + + Example: + + ```javascript + App.NavigationController = Ember.Controller.extend({ + who: "world" + }); + ``` + + ```handlebars + + Hello, {{who}}. + ``` + + ```handelbars + +

    My great app

    + {{render "navigation"}} + ``` + + ```html +

    My great app

    +
    + Hello, world. +
    + ``` + + Optionally you may provide a second argument: a property path + that will be bound to the `model` property of the controller. + + If a `model` property path is specified, then a new instance of the + controller will be created and `{{render}}` can be used multiple times + with the same name. + + For example if you had this `author` template. + + ```handlebars +
    + Written by {{firstName}} {{lastName}}. + Total Posts: {{postCount}} +
    + ``` + + You could render it inside the `post` template using the `render` helper. + + ```handlebars +
    +

    {{title}}

    +
    {{body}}
    + {{render "author" author}} +
    + ``` + + @method render + @for Ember.Handlebars.helpers + @param {String} name + @param {Object?} contextString + @param {Hash} options + @return {String} HTML string + */ + __exports__["default"] = function renderHelper(name, contextString, options) { + var length = arguments.length; + var contextProvided = length === 3; + var container, router, controller, view, context, lookupOptions; + + container = (options || contextString).data.keywords.controller.container; + router = container.lookup('router:main'); + + if (length === 2) { + // use the singleton controller + options = contextString; + contextString = undefined; + Ember.assert("You can only use the {{render}} helper once without a model object as its second argument, as in {{render \"post\" post}}.", !router || !router._lookupActiveView(name)); + } else if (length === 3) { + // create a new controller + context = handlebarsGet(options.contexts[1], contextString, options); + } else { + throw new EmberError("You must pass a templateName to render"); + } + + Ember.deprecate("Using a quoteless parameter with {{render}} is deprecated. Please update to quoted usage '{{render \"" + name + "\"}}.", options.types[0] !== 'ID'); + + // # legacy namespace + name = name.replace(/\//g, '.'); + // \ legacy slash as namespace support + + + view = container.lookup('view:' + name) || container.lookup('view:default'); + + // provide controller override + var controllerName = options.hash.controller || name; + var controllerFullName = 'controller:' + controllerName; + + if (options.hash.controller) { + Ember.assert("The controller name you supplied '" + controllerName + "' did not resolve to a controller.", container.has(controllerFullName)); + } + + var parentController = options.data.keywords.controller; + + // choose name + if (length > 2) { + var factory = container.lookupFactory(controllerFullName) || + generateControllerFactory(container, controllerName, context); + + controller = factory.create({ + model: context, + parentController: parentController, + target: parentController + }); + + view.one('willDestroyElement', function() { + controller.destroy(); + }); + } else { + controller = container.lookup(controllerFullName) || + generateController(container, controllerName); + + controller.setProperties({ + target: parentController, + parentController: parentController + }); + } + + var root = options.contexts[1]; + + if (root) { + view.registerObserver(root, contextString, function() { + controller.set('model', handlebarsGet(root, contextString, options)); + }); + } + + options.hash.viewName = camelize(name); + + var templateName = 'template:' + name; + Ember.assert("You used `{{render '" + name + "'}}`, but '" + name + "' can not be found as either a template or a view.", container.has("view:" + name) || container.has(templateName) || options.fn); + options.hash.template = container.lookup(templateName); + + options.hash.controller = controller; + + if (router && !context) { + router._connectActiveView(name, view); + } + + options.helperName = options.helperName || ('render "' + name + '"'); + + ViewHelper.instanceHelper(this, view, options); + } + }); +enifed("ember-routing-handlebars/helpers/shared", + ["ember-metal/property_get","ember-metal/array","ember-runtime/mixins/controller","ember-handlebars/ext","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var map = __dependency2__.map; + var ControllerMixin = __dependency3__["default"]; + var handlebarsResolve = __dependency4__.resolveParams; + var handlebarsGet = __dependency4__.handlebarsGet; + var typeOf = __dependency5__.typeOf; + var get = __dependency1__.get; + + function routeArgs(targetRouteName, models, queryParams) { + var args = []; + if (typeOf(targetRouteName) === 'string') { + args.push('' + targetRouteName); + } + args.push.apply(args, models); + args.push({ queryParams: queryParams }); + return args; + } + + __exports__.routeArgs = routeArgs;function getActiveTargetName(router) { + var handlerInfos = router.activeTransition ? + router.activeTransition.state.handlerInfos : + router.state.handlerInfos; + return handlerInfos[handlerInfos.length - 1].name; + } + + __exports__.getActiveTargetName = getActiveTargetName;function resolveParams(context, params, options) { + return map.call(resolvePaths(context, params, options), function(path, i) { + if (null === path) { + // Param was string/number, not a path, so just return raw string/number. + return params[i]; + } else { + return handlebarsGet(context, path, options); + } + }); + } + + __exports__.resolveParams = resolveParams;function stashParamNames(router, handlerInfos) { + if (handlerInfos._namesStashed) { return; } + + // This helper exists because router.js/route-recognizer.js awkwardly + // keeps separate a handlerInfo's list of parameter names depending + // on whether a URL transition or named transition is happening. + // Hopefully we can remove this in the future. + var targetRouteName = handlerInfos[handlerInfos.length-1].name; + var recogHandlers = router.router.recognizer.handlersFor(targetRouteName); + var dynamicParent = null; + + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var handlerInfo = handlerInfos[i]; + var names = recogHandlers[i].names; + + if (names.length) { + dynamicParent = handlerInfo; + } + + handlerInfo._names = names; + + var route = handlerInfo.handler; + route._stashNames(handlerInfo, dynamicParent); + } + + handlerInfos._namesStashed = true; + } + + __exports__.stashParamNames = stashParamNames;function resolvePaths(context, params, options) { + var resolved = handlebarsResolve(context, params, options); + var types = options.types; + + return map.call(resolved, function(object, i) { + if (types[i] === 'ID') { + return unwrap(object, params[i]); + } else { + return null; + } + }); + + function unwrap(object, path) { + if (path === 'controller') { return path; } + + if (ControllerMixin.detect(object)) { + return unwrap(get(object, 'model'), path ? path + '.model' : 'model'); + } else { + return path; + } + } + } + + __exports__.resolvePaths = resolvePaths; + }); +enifed("ember-routing", + ["ember-handlebars","ember-metal/core","ember-routing/ext/run_loop","ember-routing/ext/controller","ember-routing/ext/view","ember-routing/location/api","ember-routing/location/none_location","ember-routing/location/hash_location","ember-routing/location/history_location","ember-routing/location/auto_location","ember-routing/system/generate_controller","ember-routing/system/controller_for","ember-routing/system/dsl","ember-routing/system/router","ember-routing/system/route","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __exports__) { + "use strict"; + /** + Ember Routing + + @module ember + @submodule ember-routing + @requires ember-views + */ + + var EmberHandlebars = __dependency1__["default"]; + var Ember = __dependency2__["default"]; + + // ES6TODO: Cleanup modules with side-effects below + + var EmberLocation = __dependency6__["default"]; + var NoneLocation = __dependency7__["default"]; + var HashLocation = __dependency8__["default"]; + var HistoryLocation = __dependency9__["default"]; + var AutoLocation = __dependency10__["default"]; + + var generateControllerFactory = __dependency11__.generateControllerFactory; + var generateController = __dependency11__["default"]; + var controllerFor = __dependency12__["default"]; + var RouterDSL = __dependency13__["default"]; + var Router = __dependency14__["default"]; + var Route = __dependency15__["default"]; + + Ember.Location = EmberLocation; + Ember.AutoLocation = AutoLocation; + Ember.HashLocation = HashLocation; + Ember.HistoryLocation = HistoryLocation; + Ember.NoneLocation = NoneLocation; + + Ember.controllerFor = controllerFor; + Ember.generateControllerFactory = generateControllerFactory; + Ember.generateController = generateController; + Ember.RouterDSL = RouterDSL; + Ember.Router = Router; + Ember.Route = Route; + + __exports__["default"] = Ember; + }); +enifed("ember-routing/ext/controller", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/computed","ember-metal/utils","ember-metal/merge","ember-metal/enumerable_utils","ember-runtime/mixins/controller","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES, deprecate + var get = __dependency2__.get; + var set = __dependency3__.set; + var computed = __dependency4__.computed; + var typeOf = __dependency5__.typeOf; + var meta = __dependency5__.meta; + var merge = __dependency6__["default"]; + var map = __dependency7__.map; + + var ControllerMixin = __dependency8__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + ControllerMixin.reopen({ + concatenatedProperties: ['queryParams', '_pCacheMeta'], + + init: function() { + this._super.apply(this, arguments); + listenForQueryParamChanges(this); + }, + + /** + @property queryParams + @public + */ + queryParams: null, + + /** + @property _qpDelegate + @private + */ + _qpDelegate: null, + + /** + @property _normalizedQueryParams + @private + */ + _normalizedQueryParams: computed(function() { + var m = meta(this); + if (m.proto !== this) { + return get(m.proto, '_normalizedQueryParams'); + } + + var queryParams = get(this, 'queryParams'); + if (queryParams._qpMap) { + return queryParams._qpMap; + } + + var qpMap = queryParams._qpMap = {}; + + for (var i = 0, len = queryParams.length; i < len; ++i) { + accumulateQueryParamDescriptors(queryParams[i], qpMap); + } + + return qpMap; + }), + + /** + @property _cacheMeta + @private + */ + _cacheMeta: computed(function() { + var m = meta(this); + if (m.proto !== this) { + return get(m.proto, '_cacheMeta'); + } + + var cacheMeta = {}; + var qpMap = get(this, '_normalizedQueryParams'); + for (var prop in qpMap) { + if (!qpMap.hasOwnProperty(prop)) { continue; } + + var qp = qpMap[prop]; + var scope = qp.scope; + var parts; + + if (scope === 'controller') { + parts = []; + } + + cacheMeta[prop] = { + parts: parts, // provided by route if 'model' scope + values: null, // provided by route + scope: scope, + prefix: "", + def: get(this, prop) + }; + } + + return cacheMeta; + }), + + /** + @method _updateCacheParams + @private + */ + _updateCacheParams: function(params) { + var cacheMeta = get(this, '_cacheMeta'); + for (var prop in cacheMeta) { + if (!cacheMeta.hasOwnProperty(prop)) { continue; } + var propMeta = cacheMeta[prop]; + propMeta.values = params; + + var cacheKey = this._calculateCacheKey(propMeta.prefix, propMeta.parts, propMeta.values); + var cache = this._bucketCache; + + if (cache) { + var value = cache.lookup(cacheKey, prop, propMeta.def); + set(this, prop, value); + } + } + }, + + /** + @method _qpChanged + @private + */ + _qpChanged: function(controller, _prop) { + var prop = _prop.substr(0, _prop.length-3); + var cacheMeta = get(controller, '_cacheMeta'); + var propCache = cacheMeta[prop]; + var cacheKey = controller._calculateCacheKey(propCache.prefix || "", propCache.parts, propCache.values); + var value = get(controller, prop); + + // 1. Update model-dep cache + var cache = this._bucketCache; + if (cache) { + controller._bucketCache.stash(cacheKey, prop, value); + } + + // 2. Notify a delegate (e.g. to fire a qp transition) + var delegate = controller._qpDelegate; + if (delegate) { + delegate(controller, prop); + } + }, + + /** + @method _calculateCacheKey + @private + */ + _calculateCacheKey: function(prefix, _parts, values) { + var parts = _parts || [], suffixes = ""; + for (var i = 0, len = parts.length; i < len; ++i) { + var part = parts[i]; + var value = get(values, part); + suffixes += "::" + part + ":" + value; + } + return prefix + suffixes.replace(ALL_PERIODS_REGEX, '-'); + }, + + /** + Transition the application into another route. The route may + be either a single route or route path: + + ```javascript + aController.transitionToRoute('blogPosts'); + aController.transitionToRoute('blogPosts.recentEntries'); + ``` + + Optionally supply a model for the route in question. The model + will be serialized into the URL using the `serialize` hook of + the route: + + ```javascript + aController.transitionToRoute('blogPost', aPost); + ``` + + If a literal is passed (such as a number or a string), it will + be treated as an identifier instead. In this case, the `model` + hook of the route will be triggered: + + ```javascript + aController.transitionToRoute('blogPost', 1); + ``` + + Multiple models will be applied last to first recursively up the + resource tree. + + ```javascript + App.Router.map(function() { + this.resource('blogPost', {path:':blogPostId'}, function(){ + this.resource('blogComment', {path: ':blogCommentId'}); + }); + }); + + aController.transitionToRoute('blogComment', aPost, aComment); + aController.transitionToRoute('blogComment', 1, 13); + ``` + + It is also possible to pass a URL (a string that starts with a + `/`). This is intended for testing and debugging purposes and + should rarely be used in production code. + + ```javascript + aController.transitionToRoute('/'); + aController.transitionToRoute('/blog/post/1/comment/13'); + ``` + + See also [replaceRoute](/api/classes/Ember.ControllerMixin.html#method_replaceRoute). + + @param {String} name the name of the route or a URL + @param {...Object} models the model(s) or identifier(s) to be used + while transitioning to the route. + @for Ember.ControllerMixin + @method transitionToRoute + */ + transitionToRoute: function() { + // target may be either another controller or a router + var target = get(this, 'target'); + var method = target.transitionToRoute || target.transitionTo; + return method.apply(target, arguments); + }, + + /** + @deprecated + @for Ember.ControllerMixin + @method transitionTo + */ + transitionTo: function() { + Ember.deprecate("transitionTo is deprecated. Please use transitionToRoute."); + return this.transitionToRoute.apply(this, arguments); + }, + + /** + Transition into another route while replacing the current URL, if possible. + This will replace the current history entry instead of adding a new one. + Beside that, it is identical to `transitionToRoute` in all other respects. + + ```javascript + aController.replaceRoute('blogPosts'); + aController.replaceRoute('blogPosts.recentEntries'); + ``` + + Optionally supply a model for the route in question. The model + will be serialized into the URL using the `serialize` hook of + the route: + + ```javascript + aController.replaceRoute('blogPost', aPost); + ``` + + If a literal is passed (such as a number or a string), it will + be treated as an identifier instead. In this case, the `model` + hook of the route will be triggered: + + ```javascript + aController.replaceRoute('blogPost', 1); + ``` + + Multiple models will be applied last to first recursively up the + resource tree. + + ```javascript + App.Router.map(function() { + this.resource('blogPost', {path:':blogPostId'}, function(){ + this.resource('blogComment', {path: ':blogCommentId'}); + }); + }); + + aController.replaceRoute('blogComment', aPost, aComment); + aController.replaceRoute('blogComment', 1, 13); + ``` + + It is also possible to pass a URL (a string that starts with a + `/`). This is intended for testing and debugging purposes and + should rarely be used in production code. + + ```javascript + aController.replaceRoute('/'); + aController.replaceRoute('/blog/post/1/comment/13'); + ``` + + @param {String} name the name of the route or a URL + @param {...Object} models the model(s) or identifier(s) to be used + while transitioning to the route. + @for Ember.ControllerMixin + @method replaceRoute + */ + replaceRoute: function() { + // target may be either another controller or a router + var target = get(this, 'target'); + var method = target.replaceRoute || target.replaceWith; + return method.apply(target, arguments); + }, + + /** + @deprecated + @for Ember.ControllerMixin + @method replaceWith + */ + replaceWith: function() { + Ember.deprecate("replaceWith is deprecated. Please use replaceRoute."); + return this.replaceRoute.apply(this, arguments); + } + }); + + var ALL_PERIODS_REGEX = /\./g; + + function accumulateQueryParamDescriptors(_desc, accum) { + var desc = _desc, tmp; + if (typeOf(desc) === 'string') { + tmp = {}; + tmp[desc] = { as: null }; + desc = tmp; + } + + for (var key in desc) { + if (!desc.hasOwnProperty(key)) { return; } + + var singleDesc = desc[key]; + if (typeOf(singleDesc) === 'string') { + singleDesc = { as: singleDesc }; + } + + tmp = accum[key] || { as: null, scope: 'model' }; + merge(tmp, singleDesc); + + accum[key] = tmp; + } + } + + function listenForQueryParamChanges(controller) { + var qpMap = get(controller, '_normalizedQueryParams'); + for (var prop in qpMap) { + if (!qpMap.hasOwnProperty(prop)) { continue; } + controller.addObserver(prop + '.[]', controller, controller._qpChanged); + } + } + + + __exports__["default"] = ControllerMixin; + }); +enifed("ember-routing/ext/run_loop", + ["ember-metal/run_loop"], + function(__dependency1__) { + "use strict"; + var run = __dependency1__["default"]; + + /** + @module ember + @submodule ember-views + */ + + // Add a new named queue after the 'actions' queue (where RSVP promises + // resolve), which is used in router transitions to prevent unnecessary + // loading state entry if all context promises resolve on the + // 'actions' queue first. + + var queues = run.queues; + run._addQueue('routerTransitions', 'actions'); + }); +enifed("ember-routing/ext/view", + ["ember-metal/property_get","ember-metal/property_set","ember-metal/run_loop","ember-views/views/view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var set = __dependency2__.set; + var run = __dependency3__["default"]; + var EmberView = __dependency4__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + EmberView.reopen({ + + /** + Sets the private `_outlets` object on the view. + + @method init + */ + init: function() { + set(this, '_outlets', {}); + this._super(); + }, + + /** + Manually fill any of a view's `{{outlet}}` areas with the + supplied view. + + Example + + ```javascript + var MyView = Ember.View.extend({ + template: Ember.Handlebars.compile('Child view: {{outlet "main"}} ') + }); + var myView = MyView.create(); + myView.appendTo('body'); + // The html for myView now looks like: + //
    Child view:
    + + var FooView = Ember.View.extend({ + template: Ember.Handlebars.compile('

    Foo

    ') + }); + var fooView = FooView.create(); + myView.connectOutlet('main', fooView); + // The html for myView now looks like: + //
    Child view: + //

    Foo

    + //
    + ``` + @method connectOutlet + @param {String} outletName A unique name for the outlet + @param {Object} view An Ember.View + */ + connectOutlet: function(outletName, view) { + if (this._pendingDisconnections) { + delete this._pendingDisconnections[outletName]; + } + + if (this._hasEquivalentView(outletName, view)) { + view.destroy(); + return; + } + + var outlets = get(this, '_outlets'); + var container = get(this, 'container'); + var router = container && container.lookup('router:main'); + var renderedName = get(view, 'renderedName'); + + set(outlets, outletName, view); + + if (router && renderedName) { + router._connectActiveView(renderedName, view); + } + }, + + /** + Determines if the view has already been created by checking if + the view has the same constructor, template, and context as the + view in the `_outlets` object. + + @private + @method _hasEquivalentView + @param {String} outletName The name of the outlet we are checking + @param {Object} view An Ember.View + @return {Boolean} + */ + _hasEquivalentView: function(outletName, view) { + var existingView = get(this, '_outlets.'+outletName); + return existingView && + existingView.constructor === view.constructor && + existingView.get('template') === view.get('template') && + existingView.get('context') === view.get('context'); + }, + + /** + Removes an outlet from the view. + + Example + + ```javascript + var MyView = Ember.View.extend({ + template: Ember.Handlebars.compile('Child view: {{outlet "main"}} ') + }); + var myView = MyView.create(); + myView.appendTo('body'); + // myView's html: + //
    Child view:
    + + var FooView = Ember.View.extend({ + template: Ember.Handlebars.compile('

    Foo

    ') + }); + var fooView = FooView.create(); + myView.connectOutlet('main', fooView); + // myView's html: + //
    Child view: + //

    Foo

    + //
    + + myView.disconnectOutlet('main'); + // myView's html: + //
    Child view:
    + ``` + + @method disconnectOutlet + @param {String} outletName The name of the outlet to be removed + */ + disconnectOutlet: function(outletName) { + if (!this._pendingDisconnections) { + this._pendingDisconnections = {}; + } + this._pendingDisconnections[outletName] = true; + run.once(this, '_finishDisconnections'); + }, + + /** + Gets an outlet that is pending disconnection and then + nullifys the object on the `_outlet` object. + + @private + @method _finishDisconnections + */ + _finishDisconnections: function() { + if (this.isDestroyed) return; // _outlets will be gone anyway + var outlets = get(this, '_outlets'); + var pendingDisconnections = this._pendingDisconnections; + this._pendingDisconnections = null; + + for (var outletName in pendingDisconnections) { + set(outlets, outletName, null); + } + } + }); + + __exports__["default"] = EmberView; + }); +enifed("ember-routing/location/api", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // deprecate, assert + var get = __dependency2__.get; + var set = __dependency3__.set; + + /** + @module ember + @submodule ember-routing + */ + + /** + Ember.Location returns an instance of the correct implementation of + the `location` API. + + ## Implementations + + You can pass an implementation name (`hash`, `history`, `none`) to force a + particular implementation to be used in your application. + + ### HashLocation + + Using `HashLocation` results in URLs with a `#` (hash sign) separating the + server side URL portion of the URL from the portion that is used by Ember. + This relies upon the `hashchange` event existing in the browser. + + Example: + + ```javascript + App.Router.map(function() { + this.resource('posts', function() { + this.route('new'); + }); + }); + + App.Router.reopen({ + location: 'hash' + }); + ``` + + This will result in a posts.new url of `/#/posts/new`. + + ### HistoryLocation + + Using `HistoryLocation` results in URLs that are indistinguishable from a + standard URL. This relies upon the browser's `history` API. + + Example: + + ```javascript + App.Router.map(function() { + this.resource('posts', function() { + this.route('new'); + }); + }); + + App.Router.reopen({ + location: 'history' + }); + ``` + + This will result in a posts.new url of `/posts/new`. + + Keep in mind that your server must serve the Ember app at all the routes you + define. + + ### AutoLocation + + Using `AutoLocation`, the router will use the best Location class supported by + the browser it is running in. + + Browsers that support the `history` API will use `HistoryLocation`, those that + do not, but still support the `hashchange` event will use `HashLocation`, and + in the rare case neither is supported will use `NoneLocation`. + + Example: + + ```javascript + App.Router.map(function() { + this.resource('posts', function() { + this.route('new'); + }); + }); + + App.Router.reopen({ + location: 'auto' + }); + ``` + + This will result in a posts.new url of `/posts/new` for modern browsers that + support the `history` api or `/#/posts/new` for older ones, like Internet + Explorer 9 and below. + + When a user visits a link to your application, they will be automatically + upgraded or downgraded to the appropriate `Location` class, with the URL + transformed accordingly, if needed. + + Keep in mind that since some of your users will use `HistoryLocation`, your + server must serve the Ember app at all the routes you define. + + ### NoneLocation + + Using `NoneLocation` causes Ember to not store the applications URL state + in the actual URL. This is generally used for testing purposes, and is one + of the changes made when calling `App.setupForTesting()`. + + ## Location API + + Each location implementation must provide the following methods: + + * implementation: returns the string name used to reference the implementation. + * getURL: returns the current URL. + * setURL(path): sets the current URL. + * replaceURL(path): replace the current URL (optional). + * onUpdateURL(callback): triggers the callback when the URL changes. + * formatURL(url): formats `url` to be placed into `href` attribute. + + Calling setURL or replaceURL will not trigger onUpdateURL callbacks. + + @class Location + @namespace Ember + @static + */ + __exports__["default"] = { + /** + This is deprecated in favor of using the container to lookup the location + implementation as desired. + + For example: + + ```javascript + // Given a location registered as follows: + container.register('location:history-test', HistoryTestLocation); + + // You could create a new instance via: + container.lookup('location:history-test'); + ``` + + @method create + @param {Object} options + @return {Object} an instance of an implementation of the `location` API + @deprecated Use the container to lookup the location implementation that you + need. + */ + create: function(options) { + var implementation = options && options.implementation; + Ember.assert("Ember.Location.create: you must specify a 'implementation' option", !!implementation); + + var implementationClass = this.implementations[implementation]; + Ember.assert("Ember.Location.create: " + implementation + " is not a valid implementation", !!implementationClass); + + return implementationClass.create.apply(implementationClass, arguments); + }, + + /** + This is deprecated in favor of using the container to register the + location implementation as desired. + + Example: + + ```javascript + Application.initializer({ + name: "history-test-location", + + initialize: function(container, application) { + application.register('location:history-test', HistoryTestLocation); + } + }); + ``` + + @method registerImplementation + @param {String} name + @param {Object} implementation of the `location` API + @deprecated Register your custom location implementation with the + container directly. + */ + registerImplementation: function(name, implementation) { + Ember.deprecate('Using the Ember.Location.registerImplementation is no longer supported. Register your custom location implementation with the container instead.', false); + + this.implementations[name] = implementation; + }, + + implementations: {}, + _location: window.location, + + /** + Returns the current `location.hash` by parsing location.href since browsers + inconsistently URL-decode `location.hash`. + + https://bugzilla.mozilla.org/show_bug.cgi?id=483304 + + @private + @method getHash + @since 1.4.0 + */ + _getHash: function () { + // AutoLocation has it at _location, HashLocation at .location. + // Being nice and not changing + var href = (this._location || this.location).href; + var hashIndex = href.indexOf('#'); + + if (hashIndex === -1) { + return ''; + } else { + return href.substr(hashIndex); + } + } + }; + }); +enifed("ember-routing/location/auto_location", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-routing/location/api","ember-routing/location/history_location","ember-routing/location/hash_location","ember-routing/location/none_location","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES + var get = __dependency2__.get; + var set = __dependency3__.set; + + var EmberLocation = __dependency4__["default"]; + var HistoryLocation = __dependency5__["default"]; + var HashLocation = __dependency6__["default"]; + var NoneLocation = __dependency7__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + /** + Ember.AutoLocation will select the best location option based off browser + support with the priority order: history, hash, none. + + Clean pushState paths accessed by hashchange-only browsers will be redirected + to the hash-equivalent and vice versa so future transitions are consistent. + + Keep in mind that since some of your users will use `HistoryLocation`, your + server must serve the Ember app at all the routes you define. + + @class AutoLocation + @namespace Ember + @static + */ + __exports__["default"] = { + + /** + @private + + This property is used by router:main to know whether to cancel the routing + setup process, which is needed while we redirect the browser. + + @since 1.5.1 + @property cancelRouterSetup + @default false + */ + cancelRouterSetup: false, + + /** + @private + + Will be pre-pended to path upon state change. + + @since 1.5.1 + @property rootURL + @default '/' + */ + rootURL: '/', + + /** + @private + + Attached for mocking in tests + + @since 1.5.1 + @property _window + @default window + */ + _window: window, + + /** + @private + + Attached for mocking in tests + + @property location + @default window.location + */ + _location: window.location, + + /** + @private + + Attached for mocking in tests + + @since 1.5.1 + @property _history + @default window.history + */ + _history: window.history, + + /** + @private + + Attached for mocking in tests + + @since 1.5.1 + @property _HistoryLocation + @default Ember.HistoryLocation + */ + _HistoryLocation: HistoryLocation, + + /** + @private + + Attached for mocking in tests + + @since 1.5.1 + @property _HashLocation + @default Ember.HashLocation + */ + _HashLocation: HashLocation, + + /** + @private + + Attached for mocking in tests + + @since 1.5.1 + @property _NoneLocation + @default Ember.NoneLocation + */ + _NoneLocation: NoneLocation, + + /** + @private + + Returns location.origin or builds it if device doesn't support it. + + @method _getOrigin + */ + _getOrigin: function () { + var location = this._location; + var origin = location.origin; + + // Older browsers, especially IE, don't have origin + if (!origin) { + origin = location.protocol + '//' + location.hostname; + + if (location.port) { + origin += ':' + location.port; + } + } + + return origin; + }, + + /** + @private + + We assume that if the history object has a pushState method, the host should + support HistoryLocation. + + @method _getSupportsHistory + */ + _getSupportsHistory: function () { + // Boosted from Modernizr: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/history.js + // The stock browser on Android 2.2 & 2.3 returns positive on history support + // Unfortunately support is really buggy and there is no clean way to detect + // these bugs, so we fall back to a user agent sniff :( + var userAgent = this._window.navigator.userAgent; + + // We only want Android 2, stock browser, and not Chrome which identifies + // itself as 'Mobile Safari' as well + if (userAgent.indexOf('Android 2') !== -1 && + userAgent.indexOf('Mobile Safari') !== -1 && + userAgent.indexOf('Chrome') === -1) { + return false; + } + + return !!(this._history && 'pushState' in this._history); + }, + + /** + @private + + IE8 running in IE7 compatibility mode gives false positive, so we must also + check documentMode. + + @method _getSupportsHashChange + */ + _getSupportsHashChange: function () { + var _window = this._window; + var documentMode = _window.document.documentMode; + + return ('onhashchange' in _window && (documentMode === undefined || documentMode > 7 )); + }, + + /** + @private + + Redirects the browser using location.replace, prepending the locatin.origin + to prevent phishing attempts + + @method _replacePath + */ + _replacePath: function (path) { + this._location.replace(this._getOrigin() + path); + }, + + /** + @since 1.5.1 + @private + @method _getRootURL + */ + _getRootURL: function () { + return this.rootURL; + }, + + /** + @private + + Returns the current `location.pathname`, normalized for IE inconsistencies. + + @method _getPath + */ + _getPath: function () { + var pathname = this._location.pathname; + // Various versions of IE/Opera don't always return a leading slash + if (pathname.charAt(0) !== '/') { + pathname = '/' + pathname; + } + + return pathname; + }, + + /** + @private + + Returns normalized location.hash as an alias to Ember.Location._getHash + + @since 1.5.1 + @method _getHash + */ + _getHash: EmberLocation._getHash, + + /** + @private + + Returns location.search + + @since 1.5.1 + @method _getQuery + */ + _getQuery: function () { + return this._location.search; + }, + + /** + @private + + Returns the full pathname including query and hash + + @method _getFullPath + */ + _getFullPath: function () { + return this._getPath() + this._getQuery() + this._getHash(); + }, + + /** + @private + + Returns the current path as it should appear for HistoryLocation supported + browsers. This may very well differ from the real current path (e.g. if it + starts off as a hashed URL) + + @method _getHistoryPath + */ + _getHistoryPath: function () { + var rootURL = this._getRootURL(); + var path = this._getPath(); + var hash = this._getHash(); + var query = this._getQuery(); + var rootURLIndex = path.indexOf(rootURL); + var routeHash, hashParts; + + Ember.assert('Path ' + path + ' does not start with the provided rootURL ' + rootURL, rootURLIndex === 0); + + // By convention, Ember.js routes using HashLocation are required to start + // with `#/`. Anything else should NOT be considered a route and should + // be passed straight through, without transformation. + if (hash.substr(0, 2) === '#/') { + // There could be extra hash segments after the route + hashParts = hash.substr(1).split('#'); + // The first one is always the route url + routeHash = hashParts.shift(); + + // If the path already has a trailing slash, remove the one + // from the hashed route so we don't double up. + if (path.slice(-1) === '/') { + routeHash = routeHash.substr(1); + } + + // This is the "expected" final order + path += routeHash; + path += query; + + if (hashParts.length) { + path += '#' + hashParts.join('#'); + } + } else { + path += query; + path += hash; + } + + return path; + }, + + /** + @private + + Returns the current path as it should appear for HashLocation supported + browsers. This may very well differ from the real current path. + + @method _getHashPath + */ + _getHashPath: function () { + var rootURL = this._getRootURL(); + var path = rootURL; + var historyPath = this._getHistoryPath(); + var routePath = historyPath.substr(rootURL.length); + + if (routePath !== '') { + if (routePath.charAt(0) !== '/') { + routePath = '/' + routePath; + } + + path += '#' + routePath; + } + + return path; + }, + + /** + Selects the best location option based off browser support and returns an + instance of that Location class. + + @see Ember.AutoLocation + @method create + */ + create: function (options) { + if (options && options.rootURL) { + Ember.assert('rootURL must end with a trailing forward slash e.g. "/app/"', options.rootURL.charAt(options.rootURL.length-1) === '/'); + this.rootURL = options.rootURL; + } + + var historyPath, hashPath; + var cancelRouterSetup = false; + var implementationClass = this._NoneLocation; + var currentPath = this._getFullPath(); + + if (this._getSupportsHistory()) { + historyPath = this._getHistoryPath(); + + // Since we support history paths, let's be sure we're using them else + // switch the location over to it. + if (currentPath === historyPath) { + implementationClass = this._HistoryLocation; + } else { + + if (currentPath.substr(0, 2) === '/#') { + this._history.replaceState({ path: historyPath }, null, historyPath); + implementationClass = this._HistoryLocation; + } else { + cancelRouterSetup = true; + this._replacePath(historyPath); + } + } + + } else if (this._getSupportsHashChange()) { + hashPath = this._getHashPath(); + + // Be sure we're using a hashed path, otherwise let's switch over it to so + // we start off clean and consistent. We'll count an index path with no + // hash as "good enough" as well. + if (currentPath === hashPath || (currentPath === '/' && hashPath === '/#/')) { + implementationClass = this._HashLocation; + } else { + // Our URL isn't in the expected hash-supported format, so we want to + // cancel the router setup and replace the URL to start off clean + cancelRouterSetup = true; + this._replacePath(hashPath); + } + } + + var implementation = implementationClass.create.apply(implementationClass, arguments); + + if (cancelRouterSetup) { + set(implementation, 'cancelRouterSetup', true); + } + + return implementation; + } + }; + }); +enifed("ember-routing/location/hash_location", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/run_loop","ember-metal/utils","ember-runtime/system/object","ember-routing/location/api","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var get = __dependency2__.get; + var set = __dependency3__.set; + var run = __dependency4__["default"]; + var guidFor = __dependency5__.guidFor; + + var EmberObject = __dependency6__["default"]; + var EmberLocation = __dependency7__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + /** + `Ember.HashLocation` implements the location API using the browser's + hash. At present, it relies on a `hashchange` event existing in the + browser. + + @class HashLocation + @namespace Ember + @extends Ember.Object + */ + __exports__["default"] = EmberObject.extend({ + implementation: 'hash', + + init: function() { + set(this, 'location', get(this, '_location') || window.location); + }, + + /** + @private + + Returns normalized location.hash + + @since 1.5.1 + @method getHash + */ + getHash: EmberLocation._getHash, + + /** + Returns the current `location.hash`, minus the '#' at the front. + + @private + @method getURL + */ + getURL: function() { + var path = this.getHash().substr(1); + Ember.deprecate('location.hash value is ambiguous. Support for this will be removed soon. When using location: "hash|auto" your hash paths MUST begin with a forward slash. e.g. #/' + path + ' NOT #' + path, path.length === 0 || path.charAt(0) === '/'); + return path; + }, + + /** + Set the `location.hash` and remembers what was set. This prevents + `onUpdateURL` callbacks from triggering when the hash was set by + `HashLocation`. + + @private + @method setURL + @param path {String} + */ + setURL: function(path) { + get(this, 'location').hash = path; + set(this, 'lastSetURL', path); + }, + + /** + Uses location.replace to update the url without a page reload + or history modification. + + @private + @method replaceURL + @param path {String} + */ + replaceURL: function(path) { + get(this, 'location').replace('#' + path); + set(this, 'lastSetURL', path); + }, + + /** + Register a callback to be invoked when the hash changes. These + callbacks will execute when the user presses the back or forward + button, but not after `setURL` is invoked. + + @private + @method onUpdateURL + @param callback {Function} + */ + onUpdateURL: function(callback) { + var self = this; + var guid = guidFor(this); + + Ember.$(window).on('hashchange.ember-location-'+guid, function() { + run(function() { + var path = self.getURL(); + if (get(self, 'lastSetURL') === path) { return; } + + set(self, 'lastSetURL', null); + + callback(path); + }); + }); + }, + + /** + Given a URL, formats it to be placed into the page as part + of an element's `href` attribute. + + This is used, for example, when using the {{action}} helper + to generate a URL based on an event. + + @private + @method formatURL + @param url {String} + */ + formatURL: function(url) { + return '#' + url; + }, + + /** + Cleans up the HashLocation event listener. + + @private + @method willDestroy + */ + willDestroy: function() { + var guid = guidFor(this); + + Ember.$(window).off('hashchange.ember-location-'+guid); + } + }); + }); +enifed("ember-routing/location/history_location", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-runtime/system/object","ember-views/system/jquery","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES + var get = __dependency2__.get; + var set = __dependency3__.set; + var guidFor = __dependency4__.guidFor; + + var EmberObject = __dependency5__["default"]; + var jQuery = __dependency6__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + var popstateFired = false; + var supportsHistoryState = window.history && 'state' in window.history; + + /** + Ember.HistoryLocation implements the location API using the browser's + history.pushState API. + + @class HistoryLocation + @namespace Ember + @extends Ember.Object + */ + __exports__["default"] = EmberObject.extend({ + implementation: 'history', + + init: function() { + set(this, 'location', get(this, 'location') || window.location); + set(this, 'baseURL', jQuery('base').attr('href') || ''); + }, + + /** + Used to set state on first call to setURL + + @private + @method initState + */ + initState: function() { + set(this, 'history', get(this, 'history') || window.history); + this.replaceState(this.formatURL(this.getURL())); + }, + + /** + Will be pre-pended to path upon state change + + @property rootURL + @default '/' + */ + rootURL: '/', + + /** + Returns the current `location.pathname` without `rootURL` or `baseURL` + + @private + @method getURL + @return url {String} + */ + getURL: function() { + var rootURL = get(this, 'rootURL'); + var location = get(this, 'location'); + var path = location.pathname; + var baseURL = get(this, 'baseURL'); + + rootURL = rootURL.replace(/\/$/, ''); + baseURL = baseURL.replace(/\/$/, ''); + + var url = path.replace(baseURL, '').replace(rootURL, ''); + var search = location.search || ''; + + url += search; + + return url; + }, + + /** + Uses `history.pushState` to update the url without a page reload. + + @private + @method setURL + @param path {String} + */ + setURL: function(path) { + var state = this.getState(); + path = this.formatURL(path); + + if (!state || state.path !== path) { + this.pushState(path); + } + }, + + /** + Uses `history.replaceState` to update the url without a page reload + or history modification. + + @private + @method replaceURL + @param path {String} + */ + replaceURL: function(path) { + var state = this.getState(); + path = this.formatURL(path); + + if (!state || state.path !== path) { + this.replaceState(path); + } + }, + + /** + Get the current `history.state`. Checks for if a polyfill is + required and if so fetches this._historyState. The state returned + from getState may be null if an iframe has changed a window's + history. + + @private + @method getState + @return state {Object} + */ + getState: function() { + return supportsHistoryState ? get(this, 'history').state : this._historyState; + }, + + /** + Pushes a new state. + + @private + @method pushState + @param path {String} + */ + pushState: function(path) { + var state = { path: path }; + + get(this, 'history').pushState(state, null, path); + + // store state if browser doesn't support `history.state` + if (!supportsHistoryState) { + this._historyState = state; + } + + // used for webkit workaround + this._previousURL = this.getURL(); + }, + + /** + Replaces the current state. + + @private + @method replaceState + @param path {String} + */ + replaceState: function(path) { + var state = { path: path }; + + get(this, 'history').replaceState(state, null, path); + + // store state if browser doesn't support `history.state` + if (!supportsHistoryState) { + this._historyState = state; + } + + // used for webkit workaround + this._previousURL = this.getURL(); + }, + + /** + Register a callback to be invoked whenever the browser + history changes, including using forward and back buttons. + + @private + @method onUpdateURL + @param callback {Function} + */ + onUpdateURL: function(callback) { + var guid = guidFor(this); + var self = this; + + jQuery(window).on('popstate.ember-location-'+guid, function(e) { + // Ignore initial page load popstate event in Chrome + if (!popstateFired) { + popstateFired = true; + if (self.getURL() === self._previousURL) { return; } + } + callback(self.getURL()); + }); + }, + + /** + Used when using `{{action}}` helper. The url is always appended to the rootURL. + + @private + @method formatURL + @param url {String} + @return formatted url {String} + */ + formatURL: function(url) { + var rootURL = get(this, 'rootURL'); + var baseURL = get(this, 'baseURL'); + + if (url !== '') { + rootURL = rootURL.replace(/\/$/, ''); + baseURL = baseURL.replace(/\/$/, ''); + } else if(baseURL.match(/^\//) && rootURL.match(/^\//)) { + baseURL = baseURL.replace(/\/$/, ''); + } + + return baseURL + rootURL + url; + }, + + /** + Cleans up the HistoryLocation event listener. + + @private + @method willDestroy + */ + willDestroy: function() { + var guid = guidFor(this); + + jQuery(window).off('popstate.ember-location-'+guid); + } + }); + }); +enifed("ember-routing/location/none_location", + ["ember-metal/property_get","ember-metal/property_set","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var set = __dependency2__.set; + var EmberObject = __dependency3__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + /** + Ember.NoneLocation does not interact with the browser. It is useful for + testing, or when you need to manage state with your Router, but temporarily + don't want it to muck with the URL (for example when you embed your + application in a larger page). + + @class NoneLocation + @namespace Ember + @extends Ember.Object + */ + __exports__["default"] = EmberObject.extend({ + implementation: 'none', + path: '', + + /** + Returns the current path. + + @private + @method getURL + @return {String} path + */ + getURL: function() { + return get(this, 'path'); + }, + + /** + Set the path and remembers what was set. Using this method + to change the path will not invoke the `updateURL` callback. + + @private + @method setURL + @param path {String} + */ + setURL: function(path) { + set(this, 'path', path); + }, + + /** + Register a callback to be invoked when the path changes. These + callbacks will execute when the user presses the back or forward + button, but not after `setURL` is invoked. + + @private + @method onUpdateURL + @param callback {Function} + */ + onUpdateURL: function(callback) { + this.updateCallback = callback; + }, + + /** + Sets the path and calls the `updateURL` callback. + + @private + @method handleURL + @param callback {Function} + */ + handleURL: function(url) { + set(this, 'path', url); + this.updateCallback(url); + }, + + /** + Given a URL, formats it to be placed into the page as part + of an element's `href` attribute. + + This is used, for example, when using the {{action}} helper + to generate a URL based on an event. + + @private + @method formatURL + @param url {String} + @return {String} url + */ + formatURL: function(url) { + // The return value is not overly meaningful, but we do not want to throw + // errors when test code renders templates containing {{action href=true}} + // helpers. + return url; + } + }); + }); +enifed("ember-routing/system/cache", + ["ember-runtime/system/object","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var EmberObject = __dependency1__["default"]; + + __exports__["default"] = EmberObject.extend({ + init: function() { + this.cache = {}; + }, + has: function(bucketKey) { + return bucketKey in this.cache; + }, + stash: function(bucketKey, key, value) { + var bucket = this.cache[bucketKey]; + if (!bucket) { + bucket = this.cache[bucketKey] = {}; + } + bucket[key] = value; + }, + lookup: function(bucketKey, prop, defaultValue) { + var cache = this.cache; + if (!(bucketKey in cache)) { + return defaultValue; + } + var bucket = cache[bucketKey]; + if (prop in bucket) { + return bucket[prop]; + } else { + return defaultValue; + } + }, + cache: null + }); + }); +enifed("ember-routing/system/controller_for", + ["exports"], + function(__exports__) { + "use strict"; + /** + @module ember + @submodule ember-routing + */ + + /** + + Finds a controller instance. + + @for Ember + @method controllerFor + @private + */ + __exports__["default"] = function controllerFor(container, controllerName, lookupOptions) { + return container.lookup('controller:' + controllerName, lookupOptions); + } + }); +enifed("ember-routing/system/dsl", + ["ember-metal/core","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES, assert + + /** + @module ember + @submodule ember-routing + */ + + function DSL(name) { + this.parent = name; + this.matches = []; + } + __exports__["default"] = DSL; + + DSL.prototype = { + route: function(name, options, callback) { + if (arguments.length === 2 && typeof options === 'function') { + callback = options; + options = {}; + } + + if (arguments.length === 1) { + options = {}; + } + + var type = options.resetNamespace === true ? 'resource' : 'route'; + Ember.assert("'basic' cannot be used as a " + type + " name.", name !== 'basic'); + + + if (typeof options.path !== 'string') { + options.path = "/" + name; + } + + if (canNest(this) && options.resetNamespace !== true) { + name = this.parent + "." + name; + } + + if (callback) { + var dsl = new DSL(name); + route(dsl, 'loading'); + route(dsl, 'error', { path: "/_unused_dummy_error_path_route_" + name + "/:error" }); + + if (callback) { callback.call(dsl); } + + this.push(options.path, name, dsl.generate()); + } else { + this.push(options.path, name, null); + } + + }, + + push: function(url, name, callback) { + var parts = name.split('.'); + if (url === "" || url === "/" || parts[parts.length-1] === "index") { this.explicitIndex = true; } + + this.matches.push([url, name, callback]); + }, + + resource: function(name, options, callback) { + if (arguments.length === 2 && typeof options === 'function') { + callback = options; + options = {}; + } + + if (arguments.length === 1) { + options = {}; + } + + options.resetNamespace = true; + this.route(name, options, callback); + }, + + generate: function() { + var dslMatches = this.matches; + + if (!this.explicitIndex) { + route(this, "index", { path: "/" }); + } + + return function(match) { + for (var i=0, l=dslMatches.length; i " + fullName, { fullName: fullName }); + } + + return instance; + } + }); +enifed("ember-routing/system/route", + ["ember-metal/core","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/get_properties","ember-metal/enumerable_utils","ember-metal/is_none","ember-metal/computed","ember-metal/merge","ember-metal/utils","ember-metal/run_loop","ember-metal/keys","ember-runtime/copy","ember-runtime/system/string","ember-runtime/system/object","ember-runtime/mixins/action_handler","ember-routing/system/generate_controller","ember-routing-handlebars/helpers/shared","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __dependency18__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES, K, A, deprecate, assert, Logger + var EmberError = __dependency2__["default"]; + var get = __dependency3__.get; + var set = __dependency4__.set; + var getProperties = __dependency5__["default"]; + var forEach = __dependency6__.forEach; + var replace = __dependency6__.replace; + var isNone = __dependency7__.isNone; + var computed = __dependency8__.computed; + var merge = __dependency9__["default"]; + var isArray = __dependency10__.isArray; + var typeOf = __dependency10__.typeOf; + var run = __dependency11__["default"]; + var keys = __dependency12__["default"]; + var copy = __dependency13__["default"]; + var classify = __dependency14__.classify; + var fmt = __dependency14__.fmt; + var EmberObject = __dependency15__["default"]; + var ActionHandler = __dependency16__["default"]; + var generateController = __dependency17__["default"]; + var stashParamNames = __dependency18__.stashParamNames; + + /** + @module ember + @submodule ember-routing + */ + + /** + The `Ember.Route` class is used to define individual routes. Refer to + the [routing guide](http://emberjs.com/guides/routing/) for documentation. + + @class Route + @namespace Ember + @extends Ember.Object + @uses Ember.ActionHandler + */ + var Route = EmberObject.extend(ActionHandler, { + /** + Configuration hash for this route's queryParams. The possible + configuration options and their defaults are as follows + (assuming a query param whose URL key is `page`): + + ```js + queryParams: { + page: { + // By default, controller query param properties don't + // cause a full transition when they are changed, but + // rather only cause the URL to update. Setting + // `refreshModel` to true will cause an "in-place" + // transition to occur, whereby the model hooks for + // this route (and any child routes) will re-fire, allowing + // you to reload models (e.g., from the server) using the + // updated query param values. + refreshModel: false, + + // By default, changes to controller query param properties + // cause the URL to update via `pushState`, which means an + // item will be added to the browser's history, allowing + // you to use the back button to restore the app to the + // previous state before the query param property was changed. + // Setting `replace` to true will use `replaceState` (or its + // hash location equivalent), which causes no browser history + // item to be added. This options name and default value are + // the same as the `link-to` helper's `replace` option. + replace: false + } + } + ``` + + @property queryParams + @for Ember.Route + @type Hash + */ + queryParams: {}, + + /** + @private + + @property _qp + */ + _qp: computed(function() { + var controllerName = this.controllerName || this.routeName; + var controllerClass = this.container.lookupFactory('controller:' + controllerName); + + if (!controllerClass) { + return defaultQPMeta; + } + + var controllerProto = controllerClass.proto(); + var qpProps = get(controllerProto, '_normalizedQueryParams'); + var cacheMeta = get(controllerProto, '_cacheMeta'); + + var qps = [], map = {}, self = this; + for (var propName in qpProps) { + if (!qpProps.hasOwnProperty(propName)) { continue; } + + var desc = qpProps[propName]; + var urlKey = desc.as || this.serializeQueryParamKey(propName); + var defaultValue = get(controllerProto, propName); + + if (isArray(defaultValue)) { + defaultValue = Ember.A(defaultValue.slice()); + } + + var type = typeOf(defaultValue); + var defaultValueSerialized = this.serializeQueryParam(defaultValue, urlKey, type); + var fprop = controllerName + ':' + propName; + var qp = { + def: defaultValue, + sdef: defaultValueSerialized, + type: type, + urlKey: urlKey, + prop: propName, + fprop: fprop, + ctrl: controllerName, + cProto: controllerProto, + svalue: defaultValueSerialized, + cacheType: desc.scope, + route: this, + cacheMeta: cacheMeta[propName] + }; + + map[propName] = map[urlKey] = map[fprop] = qp; + qps.push(qp); + } + + return { + qps: qps, + map: map, + states: { + active: function(controller, prop) { + return self._activeQPChanged(controller, map[prop]); + }, + allowOverrides: function(controller, prop) { + return self._updatingQPChanged(controller, map[prop]); + }, + changingKeys: function(controller, prop) { + return self._updateSerializedQPValue(controller, map[prop]); + } + } + }; + }), + + /** + @private + + @property _names + */ + _names: null, + + /** + @private + + @method _stashNames + */ + _stashNames: function(_handlerInfo, dynamicParent) { + var handlerInfo = _handlerInfo; + if (this._names) { return; } + var names = this._names = handlerInfo._names; + + if (!names.length) { + handlerInfo = dynamicParent; + names = handlerInfo && handlerInfo._names || []; + } + + var qps = get(this, '_qp.qps'); + var len = qps.length; + + var namePaths = new Array(names.length); + for (var a = 0, nlen = names.length; a < nlen; ++a) { + namePaths[a] = handlerInfo.name + '.' + names[a]; + } + + for (var i = 0; i < len; ++i) { + var qp = qps[i]; + var cacheMeta = qp.cacheMeta; + if (cacheMeta.scope === 'model') { + cacheMeta.parts = namePaths; + } + cacheMeta.prefix = qp.ctrl; + } + }, + + /** + @private + + @property _updateSerializedQPValue + */ + _updateSerializedQPValue: function(controller, qp) { + var value = get(controller, qp.prop); + qp.svalue = this.serializeQueryParam(value, qp.urlKey, qp.type); + }, + + /** + @private + + @property _activeQPChanged + */ + _activeQPChanged: function(controller, qp) { + var value = get(controller, qp.prop); + this.router._queuedQPChanges[qp.fprop] = value; + run.once(this, this._fireQueryParamTransition); + }, + + /** + @private + @method _updatingQPChanged + */ + _updatingQPChanged: function(controller, qp) { + var router = this.router; + if (!router._qpUpdates) { + router._qpUpdates = {}; + } + router._qpUpdates[qp.urlKey] = true; + }, + + mergedProperties: ['events', 'queryParams'], + + /** + @method paramsFor + */ + paramsFor: function(name) { + var route = this.container.lookup('route:' + name); + + if (!route) { + return {}; + } + + var transition = this.router.router.activeTransition; + var state = transition ? transition.state : this.router.router.state; + + var params = {}; + merge(params, state.params[name]); + merge(params, getQueryParamsFor(route, state)); + + return params; + }, + + /** + @method serializeQueryParamKey + */ + serializeQueryParamKey: function(controllerPropertyName) { + return controllerPropertyName; + }, + + /** + @method serializeQueryParam + */ + serializeQueryParam: function(value, urlKey, defaultValueType) { + // urlKey isn't used here, but anyone overriding + // can use it to provide serialization specific + // to a certain query param. + if (defaultValueType === 'array') { + return JSON.stringify(value); + } + return '' + value; + }, + + /** + @method deserializeQueryParam + */ + deserializeQueryParam: function(value, urlKey, defaultValueType) { + // urlKey isn't used here, but anyone overriding + // can use it to provide deserialization specific + // to a certain query param. + + // Use the defaultValueType of the default value (the initial value assigned to a + // controller query param property), to intelligently deserialize and cast. + if (defaultValueType === 'boolean') { + return (value === 'true') ? true : false; + } else if (defaultValueType === 'number') { + return (Number(value)).valueOf(); + } else if (defaultValueType === 'array') { + return Ember.A(JSON.parse(value)); + } + return value; + }, + + + /** + @private + @property _fireQueryParamTransition + */ + _fireQueryParamTransition: function() { + this.transitionTo({ queryParams: this.router._queuedQPChanges }); + this.router._queuedQPChanges = {}; + }, + + /** + A hook you can use to reset controller values either when the model + changes or the route is exiting. + + ```js + App.ArticlesRoute = Ember.Route.extend({ + // ... + + resetController: function (controller, isExiting, transition) { + if (isExiting) { + controller.set('page', 1); + } + } + }); + ``` + + @method resetController + @param {Controller} controller instance + @param {Boolean} isExiting + @param {Object} transition + @since 1.7.0 + */ + resetController: Ember.K, + + /** + @private + + @method exit + */ + exit: function() { + this.deactivate(); + this.teardownViews(); + }, + + /** + @private + + @method _reset + @since 1.7.0 + */ + _reset: function(isExiting, transition) { + var controller = this.controller; + + controller._qpDelegate = get(this, '_qp.states.inactive'); + + this.resetController(controller, isExiting, transition); + }, + + /** + @private + + @method enter + */ + enter: function() { + this.activate(); + }, + + /** + The name of the view to use by default when rendering this routes template. + + When rendering a template, the route will, by default, determine the + template and view to use from the name of the route itself. If you need to + define a specific view, set this property. + + This is useful when multiple routes would benefit from using the same view + because it doesn't require a custom `renderTemplate` method. For example, + the following routes will all render using the `App.PostsListView` view: + + ```js + var PostsList = Ember.Route.extend({ + viewName: 'postsList' + }); + + App.PostsIndexRoute = PostsList.extend(); + App.PostsArchivedRoute = PostsList.extend(); + ``` + + @property viewName + @type String + @default null + @since 1.4.0 + */ + viewName: null, + + /** + The name of the template to use by default when rendering this routes + template. + + This is similar with `viewName`, but is useful when you just want a custom + template without a view. + + ```js + var PostsList = Ember.Route.extend({ + templateName: 'posts/list' + }); + + App.PostsIndexRoute = PostsList.extend(); + App.PostsArchivedRoute = PostsList.extend(); + ``` + + @property templateName + @type String + @default null + @since 1.4.0 + */ + templateName: null, + + /** + The name of the controller to associate with this route. + + By default, Ember will lookup a route's controller that matches the name + of the route (i.e. `App.PostController` for `App.PostRoute`). However, + if you would like to define a specific controller to use, you can do so + using this property. + + This is useful in many ways, as the controller specified will be: + + * passed to the `setupController` method. + * used as the controller for the view being rendered by the route. + * returned from a call to `controllerFor` for the route. + + @property controllerName + @type String + @default null + @since 1.4.0 + */ + controllerName: null, + + /** + The `willTransition` action is fired at the beginning of any + attempted transition with a `Transition` object as the sole + argument. This action can be used for aborting, redirecting, + or decorating the transition from the currently active routes. + + A good example is preventing navigation when a form is + half-filled out: + + ```js + App.ContactFormRoute = Ember.Route.extend({ + actions: { + willTransition: function(transition) { + if (this.controller.get('userHasEnteredData')) { + this.controller.displayNavigationConfirm(); + transition.abort(); + } + } + } + }); + ``` + + You can also redirect elsewhere by calling + `this.transitionTo('elsewhere')` from within `willTransition`. + Note that `willTransition` will not be fired for the + redirecting `transitionTo`, since `willTransition` doesn't + fire when there is already a transition underway. If you want + subsequent `willTransition` actions to fire for the redirecting + transition, you must first explicitly call + `transition.abort()`. + + @event willTransition + @param {Transition} transition + */ + + /** + The `didTransition` action is fired after a transition has + successfully been completed. This occurs after the normal model + hooks (`beforeModel`, `model`, `afterModel`, `setupController`) + have resolved. The `didTransition` action has no arguments, + however, it can be useful for tracking page views or resetting + state on the controller. + + ```js + App.LoginRoute = Ember.Route.extend({ + actions: { + didTransition: function() { + this.controller.get('errors.base').clear(); + return true; // Bubble the didTransition event + } + } + }); + ``` + + @event didTransition + @since 1.2.0 + */ + + /** + The `loading` action is fired on the route when a route's `model` + hook returns a promise that is not already resolved. The current + `Transition` object is the first parameter and the route that + triggered the loading event is the second parameter. + + ```js + App.ApplicationRoute = Ember.Route.extend({ + actions: { + loading: function(transition, route) { + var view = Ember.View.create({ + classNames: ['app-loading'] + }) + .append(); + + this.router.one('didTransition', function () { + view.destroy(); + }); + return true; // Bubble the loading event + } + } + }); + ``` + + @event loading + @param {Transition} transition + @param {Ember.Route} route The route that triggered the loading event + @since 1.2.0 + */ + + /** + When attempting to transition into a route, any of the hooks + may return a promise that rejects, at which point an `error` + action will be fired on the partially-entered routes, allowing + for per-route error handling logic, or shared error handling + logic defined on a parent route. + + Here is an example of an error handler that will be invoked + for rejected promises from the various hooks on the route, + as well as any unhandled errors from child routes: + + ```js + App.AdminRoute = Ember.Route.extend({ + beforeModel: function() { + return Ember.RSVP.reject("bad things!"); + }, + + actions: { + error: function(error, transition) { + // Assuming we got here due to the error in `beforeModel`, + // we can expect that error === "bad things!", + // but a promise model rejecting would also + // call this hook, as would any errors encountered + // in `afterModel`. + + // The `error` hook is also provided the failed + // `transition`, which can be stored and later + // `.retry()`d if desired. + + this.transitionTo('login'); + } + } + }); + ``` + + `error` actions that bubble up all the way to `ApplicationRoute` + will fire a default error handler that logs the error. You can + specify your own global default error handler by overriding the + `error` handler on `ApplicationRoute`: + + ```js + App.ApplicationRoute = Ember.Route.extend({ + actions: { + error: function(error, transition) { + this.controllerFor('banner').displayError(error.message); + } + } + }); + ``` + @event error + @param {Error} error + @param {Transition} transition + */ + + /** + The controller associated with this route. + + Example + + ```javascript + App.FormRoute = Ember.Route.extend({ + actions: { + willTransition: function(transition) { + if (this.controller.get('userHasEnteredData') && + !confirm("Are you sure you want to abandon progress?")) { + transition.abort(); + } else { + // Bubble the `willTransition` action so that + // parent routes can decide whether or not to abort. + return true; + } + } + } + }); + ``` + + @property controller + @type Ember.Controller + @since 1.6.0 + */ + + _actions: { + + queryParamsDidChange: function(changed, totalPresent, removed) { + var totalChanged = keys(changed).concat(keys(removed)); + for (var i = 0, len = totalChanged.length; i < len; ++i) { + var urlKey = totalChanged[i]; + var options = get(this.queryParams, urlKey) || {}; + if (get(options, 'refreshModel')) { + this.refresh(); + } + } + + return true; + }, + + finalizeQueryParamChange: function(params, finalParams, transition) { + if (this.routeName !== 'application') { return true; } + + // Transition object is absent for intermediate transitions. + if (!transition) { return; } + + var handlerInfos = transition.state.handlerInfos; + var router = this.router; + var qpMeta = router._queryParamsFor(handlerInfos[handlerInfos.length-1].name); + var changes = router._qpUpdates; + var replaceUrl; + + stashParamNames(router, handlerInfos); + + for (var i = 0, len = qpMeta.qps.length; i < len; ++i) { + var qp = qpMeta.qps[i]; + var route = qp.route; + var controller = route.controller; + var presentKey = qp.urlKey in params && qp.urlKey; + + // Do a reverse lookup to see if the changed query + // param URL key corresponds to a QP property on + // this controller. + var value, svalue; + if (changes && qp.urlKey in changes) { + // Value updated in/before setupController + value = get(controller, qp.prop); + svalue = route.serializeQueryParam(value, qp.urlKey, qp.type); + } else { + if (presentKey) { + svalue = params[presentKey]; + value = route.deserializeQueryParam(svalue, qp.urlKey, qp.type); + } else { + // No QP provided; use default value. + svalue = qp.sdef; + value = copyDefaultValue(qp.def); + } + } + + controller._qpDelegate = get(this, '_qp.states.inactive'); + + var thisQueryParamChanged = (svalue !== qp.svalue); + if (thisQueryParamChanged) { + var options = get(route, 'queryParams.' + qp.urlKey) || {}; + + if (transition.queryParamsOnly && replaceUrl !== false) { + var replaceConfigValue = get(options, 'replace'); + if (replaceConfigValue) { + replaceUrl = true; + } else if (replaceConfigValue === false) { + // Explicit pushState wins over any other replaceStates. + replaceUrl = false; + } + } + + set(controller, qp.prop, value); + } + + // Stash current serialized value of controller. + qp.svalue = svalue; + + var thisQueryParamHasDefaultValue = (qp.sdef === svalue); + if (!thisQueryParamHasDefaultValue) { + finalParams.push({ + value: svalue, + visible: true, + key: presentKey || qp.urlKey + }); + } + } + + if (replaceUrl) { + transition.method('replace'); + } + + forEach(qpMeta.qps, function(qp) { + var routeQpMeta = get(qp.route, '_qp'); + var finalizedController = qp.route.controller; + finalizedController._qpDelegate = get(routeQpMeta, 'states.active'); + }); + + router._qpUpdates = null; + } + }, + + /** + @deprecated + + Please use `actions` instead. + @method events + */ + events: null, + + /** + This hook is executed when the router completely exits this route. It is + not executed when the model for the route changes. + + @method deactivate + */ + deactivate: Ember.K, + + /** + This hook is executed when the router enters the route. It is not executed + when the model for the route changes. + + @method activate + */ + activate: Ember.K, + + /** + Transition the application into another route. The route may + be either a single route or route path: + + ```javascript + this.transitionTo('blogPosts'); + this.transitionTo('blogPosts.recentEntries'); + ``` + + Optionally supply a model for the route in question. The model + will be serialized into the URL using the `serialize` hook of + the route: + + ```javascript + this.transitionTo('blogPost', aPost); + ``` + + If a literal is passed (such as a number or a string), it will + be treated as an identifier instead. In this case, the `model` + hook of the route will be triggered: + + ```javascript + this.transitionTo('blogPost', 1); + ``` + + Multiple models will be applied last to first recursively up the + resource tree. + + ```javascript + App.Router.map(function() { + this.resource('blogPost', {path:':blogPostId'}, function(){ + this.resource('blogComment', {path: ':blogCommentId'}); + }); + }); + + this.transitionTo('blogComment', aPost, aComment); + this.transitionTo('blogComment', 1, 13); + ``` + + It is also possible to pass a URL (a string that starts with a + `/`). This is intended for testing and debugging purposes and + should rarely be used in production code. + + ```javascript + this.transitionTo('/'); + this.transitionTo('/blog/post/1/comment/13'); + ``` + + See also 'replaceWith'. + + Simple Transition Example + + ```javascript + App.Router.map(function() { + this.route("index"); + this.route("secret"); + this.route("fourOhFour", { path: "*:"}); + }); + + App.IndexRoute = Ember.Route.extend({ + actions: { + moveToSecret: function(context){ + if (authorized()){ + this.transitionTo('secret', context); + } + this.transitionTo('fourOhFour'); + } + } + }); + ``` + + Transition to a nested route + + ```javascript + App.Router.map(function() { + this.resource('articles', { path: '/articles' }, function() { + this.route('new'); + }); + }); + + App.IndexRoute = Ember.Route.extend({ + actions: { + transitionToNewArticle: function() { + this.transitionTo('articles.new'); + } + } + }); + ``` + + Multiple Models Example + + ```javascript + App.Router.map(function() { + this.route("index"); + this.resource('breakfast', {path:':breakfastId'}, function(){ + this.resource('cereal', {path: ':cerealId'}); + }); + }); + + App.IndexRoute = Ember.Route.extend({ + actions: { + moveToChocolateCereal: function(){ + var cereal = { cerealId: "ChocolateYumminess"}, + breakfast = {breakfastId: "CerealAndMilk"}; + + this.transitionTo('cereal', breakfast, cereal); + } + } + }); + ``` + + @method transitionTo + @param {String} name the name of the route or a URL + @param {...Object} models the model(s) or identifier(s) to be used while + transitioning to the route. + @return {Transition} the transition object associated with this + attempted transition + */ + transitionTo: function(name, context) { + var router = this.router; + return router.transitionTo.apply(router, arguments); + }, + + /** + Perform a synchronous transition into another route without attempting + to resolve promises, update the URL, or abort any currently active + asynchronous transitions (i.e. regular transitions caused by + `transitionTo` or URL changes). + + This method is handy for performing intermediate transitions on the + way to a final destination route, and is called internally by the + default implementations of the `error` and `loading` handlers. + + @method intermediateTransitionTo + @param {String} name the name of the route + @param {...Object} models the model(s) to be used while transitioning + to the route. + @since 1.2.0 + */ + intermediateTransitionTo: function() { + var router = this.router; + router.intermediateTransitionTo.apply(router, arguments); + }, + + /** + Refresh the model on this route and any child routes, firing the + `beforeModel`, `model`, and `afterModel` hooks in a similar fashion + to how routes are entered when transitioning in from other route. + The current route params (e.g. `article_id`) will be passed in + to the respective model hooks, and if a different model is returned, + `setupController` and associated route hooks will re-fire as well. + + An example usage of this method is re-querying the server for the + latest information using the same parameters as when the route + was first entered. + + Note that this will cause `model` hooks to fire even on routes + that were provided a model object when the route was initially + entered. + + @method refresh + @return {Transition} the transition object associated with this + attempted transition + @since 1.4.0 + */ + refresh: function() { + return this.router.router.refresh(this); + }, + + /** + Transition into another route while replacing the current URL, if possible. + This will replace the current history entry instead of adding a new one. + Beside that, it is identical to `transitionTo` in all other respects. See + 'transitionTo' for additional information regarding multiple models. + + Example + + ```javascript + App.Router.map(function() { + this.route("index"); + this.route("secret"); + }); + + App.SecretRoute = Ember.Route.extend({ + afterModel: function() { + if (!authorized()){ + this.replaceWith('index'); + } + } + }); + ``` + + @method replaceWith + @param {String} name the name of the route or a URL + @param {...Object} models the model(s) or identifier(s) to be used while + transitioning to the route. + @return {Transition} the transition object associated with this + attempted transition + */ + replaceWith: function() { + var router = this.router; + return router.replaceWith.apply(router, arguments); + }, + + /** + Sends an action to the router, which will delegate it to the currently + active route hierarchy per the bubbling rules explained under `actions`. + + Example + + ```javascript + App.Router.map(function() { + this.route("index"); + }); + + App.ApplicationRoute = Ember.Route.extend({ + actions: { + track: function(arg) { + console.log(arg, 'was clicked'); + } + } + }); + + App.IndexRoute = Ember.Route.extend({ + actions: { + trackIfDebug: function(arg) { + if (debug) { + this.send('track', arg); + } + } + } + }); + ``` + + @method send + @param {String} name the name of the action to trigger + @param {...*} args + */ + send: function() { + return this.router.send.apply(this.router, arguments); + }, + + /** + This hook is the entry point for router.js + + @private + @method setup + */ + setup: function(context, transition) { + var controllerName = this.controllerName || this.routeName; + var controller = this.controllerFor(controllerName, true); + + if (!controller) { + controller = this.generateController(controllerName, context); + } + + // Assign the route's controller so that it can more easily be + // referenced in action handlers + this.controller = controller; + + if (this.setupControllers) { + Ember.deprecate("Ember.Route.setupControllers is deprecated. Please use Ember.Route.setupController(controller, model) instead."); + this.setupControllers(controller, context); + } else { + var states = get(this, '_qp.states'); + if (transition) { + // Update the model dep values used to calculate cache keys. + stashParamNames(this.router, transition.state.handlerInfos); + controller._qpDelegate = states.changingKeys; + controller._updateCacheParams(transition.params); + } + controller._qpDelegate = states.allowOverrides; + + if (transition) { + var qpValues = getQueryParamsFor(this, transition.state); + controller.setProperties(qpValues); + } + + this.setupController(controller, context, transition); + } + + if (this.renderTemplates) { + Ember.deprecate("Ember.Route.renderTemplates is deprecated. Please use Ember.Route.renderTemplate(controller, model) instead."); + this.renderTemplates(context); + } else { + this.renderTemplate(controller, context); + } + }, + + /** + This hook is the first of the route entry validation hooks + called when an attempt is made to transition into a route + or one of its children. It is called before `model` and + `afterModel`, and is appropriate for cases when: + + 1) A decision can be made to redirect elsewhere without + needing to resolve the model first. + 2) Any async operations need to occur first before the + model is attempted to be resolved. + + This hook is provided the current `transition` attempt + as a parameter, which can be used to `.abort()` the transition, + save it for a later `.retry()`, or retrieve values set + on it from a previous hook. You can also just call + `this.transitionTo` to another route to implicitly + abort the `transition`. + + You can return a promise from this hook to pause the + transition until the promise resolves (or rejects). This could + be useful, for instance, for retrieving async code from + the server that is required to enter a route. + + ```js + App.PostRoute = Ember.Route.extend({ + beforeModel: function(transition) { + if (!App.Post) { + return Ember.$.getScript('/models/post.js'); + } + } + }); + ``` + + If `App.Post` doesn't exist in the above example, + `beforeModel` will use jQuery's `getScript`, which + returns a promise that resolves after the server has + successfully retrieved and executed the code from the + server. Note that if an error were to occur, it would + be passed to the `error` hook on `Ember.Route`, but + it's also possible to handle errors specific to + `beforeModel` right from within the hook (to distinguish + from the shared error handling behavior of the `error` + hook): + + ```js + App.PostRoute = Ember.Route.extend({ + beforeModel: function(transition) { + if (!App.Post) { + var self = this; + return Ember.$.getScript('post.js').then(null, function(e) { + self.transitionTo('help'); + + // Note that the above transitionTo will implicitly + // halt the transition. If you were to return + // nothing from this promise reject handler, + // according to promise semantics, that would + // convert the reject into a resolve and the + // transition would continue. To propagate the + // error so that it'd be handled by the `error` + // hook, you would have to either + return Ember.RSVP.reject(e); + }); + } + } + }); + ``` + + @method beforeModel + @param {Transition} transition + @param {Object} queryParams the active query params for this route + @return {Promise} if the value returned from this hook is + a promise, the transition will pause until the transition + resolves. Otherwise, non-promise return values are not + utilized in any way. + */ + beforeModel: Ember.K, + + /** + This hook is called after this route's model has resolved. + It follows identical async/promise semantics to `beforeModel` + but is provided the route's resolved model in addition to + the `transition`, and is therefore suited to performing + logic that can only take place after the model has already + resolved. + + ```js + App.PostsRoute = Ember.Route.extend({ + afterModel: function(posts, transition) { + if (posts.get('length') === 1) { + this.transitionTo('post.show', posts.get('firstObject')); + } + } + }); + ``` + + Refer to documentation for `beforeModel` for a description + of transition-pausing semantics when a promise is returned + from this hook. + + @method afterModel + @param {Object} resolvedModel the value returned from `model`, + or its resolved value if it was a promise + @param {Transition} transition + @param {Object} queryParams the active query params for this handler + @return {Promise} if the value returned from this hook is + a promise, the transition will pause until the transition + resolves. Otherwise, non-promise return values are not + utilized in any way. + */ + afterModel: Ember.K, + + /** + A hook you can implement to optionally redirect to another route. + + If you call `this.transitionTo` from inside of this hook, this route + will not be entered in favor of the other hook. + + `redirect` and `afterModel` behave very similarly and are + called almost at the same time, but they have an important + distinction in the case that, from one of these hooks, a + redirect into a child route of this route occurs: redirects + from `afterModel` essentially invalidate the current attempt + to enter this route, and will result in this route's `beforeModel`, + `model`, and `afterModel` hooks being fired again within + the new, redirecting transition. Redirects that occur within + the `redirect` hook, on the other hand, will _not_ cause + these hooks to be fired again the second time around; in + other words, by the time the `redirect` hook has been called, + both the resolved model and attempted entry into this route + are considered to be fully validated. + + @method redirect + @param {Object} model the model for this route + @param {Transition} transition the transition object associated with the current transition + */ + redirect: Ember.K, + + /** + Called when the context is changed by router.js. + + @private + @method contextDidChange + */ + contextDidChange: function() { + this.currentModel = this.context; + }, + + /** + A hook you can implement to convert the URL into the model for + this route. + + ```js + App.Router.map(function() { + this.resource('post', {path: '/posts/:post_id'}); + }); + ``` + + The model for the `post` route is `App.Post.find(params.post_id)`. + + By default, if your route has a dynamic segment ending in `_id`: + + * The model class is determined from the segment (`post_id`'s + class is `App.Post`) + * The find method is called on the model class with the value of + the dynamic segment. + + Note that for routes with dynamic segments, this hook is not always + executed. If the route is entered through a transition (e.g. when + using the `link-to` Handlebars helper or the `transitionTo` method + of routes), and a model context is already provided this hook + is not called. + + A model context does not include a primitive string or number, + which does cause the model hook to be called. + + Routes without dynamic segments will always execute the model hook. + + ```js + // no dynamic segment, model hook always called + this.transitionTo('posts'); + + // model passed in, so model hook not called + thePost = store.find('post', 1); + this.transitionTo('post', thePost); + + // integer passed in, model hook is called + this.transitionTo('post', 1); + ``` + + + This hook follows the asynchronous/promise semantics + described in the documentation for `beforeModel`. In particular, + if a promise returned from `model` fails, the error will be + handled by the `error` hook on `Ember.Route`. + + Example + + ```js + App.PostRoute = Ember.Route.extend({ + model: function(params) { + return App.Post.find(params.post_id); + } + }); + ``` + + @method model + @param {Object} params the parameters extracted from the URL + @param {Transition} transition + @param {Object} queryParams the query params for this route + @return {Object|Promise} the model for this route. If + a promise is returned, the transition will pause until + the promise resolves, and the resolved value of the promise + will be used as the model for this route. + */ + model: function(params, transition) { + var match, name, sawParams, value; + + var queryParams = get(this, '_qp.map'); + + for (var prop in params) { + if (prop === 'queryParams' || (queryParams && prop in queryParams)) { + continue; + } + + if (match = prop.match(/^(.*)_id$/)) { + name = match[1]; + value = params[prop]; + } + sawParams = true; + } + + if (!name && sawParams) { return copy(params); } + else if (!name) { + if (transition.resolveIndex < 1) { return; } + + var parentModel = transition.state.handlerInfos[transition.resolveIndex-1].context; + + return parentModel; + } + + return this.findModel(name, value); + }, + + /** + @private + @method deserialize + @param {Object} params the parameters extracted from the URL + @param {Transition} transition + @return {Object|Promise} the model for this route. + + Router.js hook. + */ + deserialize: function(params, transition) { + return this.model(this.paramsFor(this.routeName), transition); + }, + + /** + + @method findModel + @param {String} type the model type + @param {Object} value the value passed to find + */ + findModel: function(){ + var store = get(this, 'store'); + return store.find.apply(store, arguments); + }, + + /** + Store property provides a hook for data persistence libraries to inject themselves. + + By default, this store property provides the exact same functionality previously + in the model hook. + + Currently, the required interface is: + + `store.find(modelName, findArguments)` + + @method store + @param {Object} store + */ + store: computed(function(){ + var container = this.container; + var routeName = this.routeName; + var namespace = get(this, 'router.namespace'); + + return { + find: function(name, value) { + var modelClass = container.lookupFactory('model:' + name); + + Ember.assert("You used the dynamic segment " + name + "_id in your route " + + routeName + ", but " + namespace + "." + classify(name) + + " did not exist and you did not override your route's `model` " + + "hook.", modelClass); + + if (!modelClass) { return; } + + Ember.assert(classify(name) + ' has no method `find`.', typeof modelClass.find === 'function'); + + return modelClass.find(value); + } + }; + }), + + /** + A hook you can implement to convert the route's model into parameters + for the URL. + + ```js + App.Router.map(function() { + this.resource('post', {path: '/posts/:post_id'}); + }); + + App.PostRoute = Ember.Route.extend({ + model: function(params) { + // the server returns `{ id: 12 }` + return jQuery.getJSON("/posts/" + params.post_id); + }, + + serialize: function(model) { + // this will make the URL `/posts/12` + return { post_id: model.id }; + } + }); + ``` + + The default `serialize` method will insert the model's `id` into the + route's dynamic segment (in this case, `:post_id`) if the segment contains '_id'. + If the route has multiple dynamic segments or does not contain '_id', `serialize` + will return `Ember.getProperties(model, params)` + + This method is called when `transitionTo` is called with a context + in order to populate the URL. + + @method serialize + @param {Object} model the route's model + @param {Array} params an Array of parameter names for the current + route (in the example, `['post_id']`. + @return {Object} the serialized parameters + */ + serialize: function(model, params) { + if (params.length < 1) { return; } + if (!model) { return; } + + var name = params[0], object = {}; + + if (/_id$/.test(name) && params.length === 1) { + object[name] = get(model, "id"); + } else { + object = getProperties(model, params); + } + + return object; + }, + + /** + A hook you can use to setup the controller for the current route. + + This method is called with the controller for the current route and the + model supplied by the `model` hook. + + By default, the `setupController` hook sets the `model` property of + the controller to the `model`. + + If you implement the `setupController` hook in your Route, it will + prevent this default behavior. If you want to preserve that behavior + when implementing your `setupController` function, make sure to call + `_super`: + + ```js + App.PhotosRoute = Ember.Route.extend({ + model: function() { + return App.Photo.find(); + }, + + setupController: function (controller, model) { + // Call _super for default behavior + this._super(controller, model); + // Implement your custom setup after + this.controllerFor('application').set('showingPhotos', true); + } + }); + ``` + + This means that your template will get a proxy for the model as its + context, and you can act as though the model itself was the context. + + The provided controller will be one resolved based on the name + of this route. + + If no explicit controller is defined, Ember will automatically create + an appropriate controller for the model. + + * if the model is an `Ember.Array` (including record arrays from Ember + Data), the controller is an `Ember.ArrayController`. + * otherwise, the controller is an `Ember.ObjectController`. + + As an example, consider the router: + + ```js + App.Router.map(function() { + this.resource('post', {path: '/posts/:post_id'}); + }); + ``` + + For the `post` route, a controller named `App.PostController` would + be used if it is defined. If it is not defined, an `Ember.ObjectController` + instance would be used. + + Example + + ```js + App.PostRoute = Ember.Route.extend({ + setupController: function(controller, model) { + controller.set('model', model); + } + }); + ``` + + @method setupController + @param {Controller} controller instance + @param {Object} model + */ + setupController: function(controller, context, transition) { + if (controller && (context !== undefined)) { + set(controller, 'model', context); + } + }, + + /** + Returns the controller for a particular route or name. + + The controller instance must already have been created, either through entering the + associated route or using `generateController`. + + ```js + App.PostRoute = Ember.Route.extend({ + setupController: function(controller, post) { + this._super(controller, post); + this.controllerFor('posts').set('currentPost', post); + } + }); + ``` + + @method controllerFor + @param {String} name the name of the route or controller + @return {Ember.Controller} + */ + controllerFor: function(name, _skipAssert) { + var container = this.container; + var route = container.lookup('route:'+name); + var controller; + + if (route && route.controllerName) { + name = route.controllerName; + } + + controller = container.lookup('controller:' + name); + + // NOTE: We're specifically checking that skipAssert is true, because according + // to the old API the second parameter was model. We do not want people who + // passed a model to skip the assertion. + Ember.assert("The controller named '"+name+"' could not be found. Make sure " + + "that this route exists and has already been entered at least " + + "once. If you are accessing a controller not associated with a " + + "route, make sure the controller class is explicitly defined.", + controller || _skipAssert === true); + + return controller; + }, + + /** + Generates a controller for a route. + + If the optional model is passed then the controller type is determined automatically, + e.g., an ArrayController for arrays. + + Example + + ```js + App.PostRoute = Ember.Route.extend({ + setupController: function(controller, post) { + this._super(controller, post); + this.generateController('posts', post); + } + }); + ``` + + @method generateController + @param {String} name the name of the controller + @param {Object} model the model to infer the type of the controller (optional) + */ + generateController: function(name, model) { + var container = this.container; + + model = model || this.modelFor(name); + + return generateController(container, name, model); + }, + + /** + Returns the model of a parent (or any ancestor) route + in a route hierarchy. During a transition, all routes + must resolve a model object, and if a route + needs access to a parent route's model in order to + resolve a model (or just reuse the model from a parent), + it can call `this.modelFor(theNameOfParentRoute)` to + retrieve it. + + Example + + ```js + App.Router.map(function() { + this.resource('post', { path: '/post/:post_id' }, function() { + this.resource('comments'); + }); + }); + + App.CommentsRoute = Ember.Route.extend({ + afterModel: function() { + this.set('post', this.modelFor('post')); + } + }); + ``` + + @method modelFor + @param {String} name the name of the route + @return {Object} the model object + */ + modelFor: function(name) { + var route = this.container.lookup('route:' + name); + var transition = this.router ? this.router.router.activeTransition : null; + + // If we are mid-transition, we want to try and look up + // resolved parent contexts on the current transitionEvent. + if (transition) { + var modelLookupName = (route && route.routeName) || name; + if (transition.resolvedModels.hasOwnProperty(modelLookupName)) { + return transition.resolvedModels[modelLookupName]; + } + } + + return route && route.currentModel; + }, + + /** + A hook you can use to render the template for the current route. + + This method is called with the controller for the current route and the + model supplied by the `model` hook. By default, it renders the route's + template, configured with the controller for the route. + + This method can be overridden to set up and render additional or + alternative templates. + + ```js + App.PostsRoute = Ember.Route.extend({ + renderTemplate: function(controller, model) { + var favController = this.controllerFor('favoritePost'); + + // Render the `favoritePost` template into + // the outlet `posts`, and display the `favoritePost` + // controller. + this.render('favoritePost', { + outlet: 'posts', + controller: favController + }); + } + }); + ``` + + @method renderTemplate + @param {Object} controller the route's controller + @param {Object} model the route's model + */ + renderTemplate: function(controller, model) { + this.render(); + }, + + /** + `render` is used to render a template into a region of another template + (indicated by an `{{outlet}}`). `render` is used both during the entry + phase of routing (via the `renderTemplate` hook) and later in response to + user interaction. + + For example, given the following minimal router and templates: + + ```js + Router.map(function() { + this.resource('photos'); + }); + ``` + + ```handlebars + +
    + {{outlet "anOutletName"}} +
    + ``` + + ```handlebars + +

    Photos

    + ``` + + You can render `photos.hbs` into the `"anOutletName"` outlet of + `application.hbs` by calling `render`: + + ```js + // posts route + Ember.Route.extend({ + renderTemplate: function(){ + this.render('posts', { + into: 'application', + outlet: 'anOutletName' + }) + } + }); + ``` + + `render` additionally allows you to supply which `view`, `controller`, and + `model` objects should be loaded and associated with the rendered template. + + + ```js + // posts route + Ember.Route.extend({ + renderTemplate: function(controller, model){ + this.render('posts', { // the template to render, referenced by name + into: 'application', // the template to render into, referenced by name + outlet: 'anOutletName', // the outlet inside `options.template` to render into. + view: 'aViewName', // the view to use for this template, referenced by name + controller: 'someControllerName', // the controller to use for this template, referenced by name + model: model // the model to set on `options.controller`. + }) + } + }); + ``` + + The string values provided for the template name, view, and controller + will eventually pass through to the resolver for lookup. See + Ember.Resolver for how these are mapped to JavaScript objects in your + application. + + Not all options need to be passed to `render`. Default values will be used + based on the name of the route specified in the router or the Route's + `controllerName`, `viewName` and and `templateName` properties. + + For example: + + ```js + // router + Router.map(function() { + this.route('index'); + this.resource('post', {path: '/posts/:post_id'}); + }); + ``` + + ```js + // post route + PostRoute = App.Route.extend({ + renderTemplate: function() { + this.render(); // all defaults apply + } + }); + ``` + + The name of the `PostRoute`, defined by the router, is `post`. + + The following equivalent default options will be applied when + the Route calls `render`: + + ```js + // + this.render('post', { // the template name associated with 'post' Route + into: 'application', // the parent route to 'post' Route + outlet: 'main', // {{outlet}} and {{outlet 'main' are synonymous}}, + view: 'post', // the view associated with the 'post' Route + controller: 'post', // the controller associated with the 'post' Route + }) + ``` + + By default the controller's `model` will be the route's model, so it does not + need to be passed unless you wish to change which model is being used. + + @method render + @param {String} name the name of the template to render + @param {Object} [options] the options + @param {String} [options.into] the template to render into, + referenced by name. Defaults to the parent template + @param {String} [options.outlet] the outlet inside `options.template` to render into. + Defaults to 'main' + @param {String} [options.controller] the controller to use for this template, + referenced by name. Defaults to the Route's paired controller + @param {String} [options.model] the model object to set on `options.controller` + Defaults to the return value of the Route's model hook + */ + render: function(name, options) { + Ember.assert("The name in the given arguments is undefined", arguments.length > 0 ? !isNone(arguments[0]) : true); + + var namePassed = typeof name === 'string' && !!name; + + if (typeof name === 'object' && !options) { + options = name; + name = this.routeName; + } + + options = options || {}; + options.namePassed = namePassed; + + var templateName; + + if (name) { + name = name.replace(/\//g, '.'); + templateName = name; + } else { + name = this.routeName; + templateName = this.templateName || name; + } + + var viewName = options.view || namePassed && name || this.viewName || name; + + var container = this.container; + var view = container.lookup('view:' + viewName); + var template = view ? view.get('template') : null; + + if (!template) { + template = container.lookup('template:' + templateName); + } + + if (!view && !template) { + Ember.assert("Could not find \"" + name + "\" template or view.", Ember.isEmpty(arguments[0])); + if (get(this.router, 'namespace.LOG_VIEW_LOOKUPS')) { + Ember.Logger.info("Could not find \"" + name + "\" template or view. Nothing will be rendered", { fullName: 'template:' + name }); + } + return; + } + + options = normalizeOptions(this, name, template, options); + view = setupView(view, container, options); + + if (options.outlet === 'main') { this.lastRenderedTemplate = name; } + + appendView(this, view, options); + }, + + /** + Disconnects a view that has been rendered into an outlet. + + You may pass any or all of the following options to `disconnectOutlet`: + + * `outlet`: the name of the outlet to clear (default: 'main') + * `parentView`: the name of the view containing the outlet to clear + (default: the view rendered by the parent route) + + Example: + + ```js + App.ApplicationRoute = App.Route.extend({ + actions: { + showModal: function(evt) { + this.render(evt.modalName, { + outlet: 'modal', + into: 'application' + }); + }, + hideModal: function(evt) { + this.disconnectOutlet({ + outlet: 'modal', + parentView: 'application' + }); + } + } + }); + ``` + + Alternatively, you can pass the `outlet` name directly as a string. + + Example: + + ```js + hideModal: function(evt) { + this.disconnectOutlet('modal'); + } + ``` + + @method disconnectOutlet + @param {Object|String} options the options hash or outlet name + */ + disconnectOutlet: function(options) { + if (!options || typeof options === "string") { + var outletName = options; + options = {}; + options.outlet = outletName; + } + options.parentView = options.parentView ? options.parentView.replace(/\//g, '.') : parentTemplate(this); + options.outlet = options.outlet || 'main'; + + var parentView = this.router._lookupActiveView(options.parentView); + if (parentView) { parentView.disconnectOutlet(options.outlet); } + }, + + willDestroy: function() { + this.teardownViews(); + }, + + /** + @private + + @method teardownViews + */ + teardownViews: function() { + // Tear down the top level view + if (this.teardownTopLevelView) { this.teardownTopLevelView(); } + + // Tear down any outlets rendered with 'into' + var teardownOutletViews = this.teardownOutletViews || []; + forEach(teardownOutletViews, function(teardownOutletView) { + teardownOutletView(); + }); + + delete this.teardownTopLevelView; + delete this.teardownOutletViews; + delete this.lastRenderedTemplate; + } + }); + + var defaultQPMeta = { + qps: [], + map: {}, + states: {} + }; + + function parentRoute(route) { + var handlerInfo = handlerInfoFor(route, route.router.router.state.handlerInfos, -1); + return handlerInfo && handlerInfo.handler; + } + + function handlerInfoFor(route, handlerInfos, _offset) { + if (!handlerInfos) { return; } + + var offset = _offset || 0, current; + for (var i=0, l=handlerInfos.length; i " + routeName, { fullName: routeName }); + } + } + + handler.routeName = name; + return handler; + }; + }, + + _setupRouter: function(router, location) { + var lastURL, emberRouter = this; + + router.getHandler = this._getHandlerFunction(); + + var doUpdateURL = function() { + location.setURL(lastURL); + }; + + router.updateURL = function(path) { + lastURL = path; + run.once(doUpdateURL); + }; + + if (location.replaceURL) { + var doReplaceURL = function() { + location.replaceURL(lastURL); + }; + + router.replaceURL = function(path) { + lastURL = path; + run.once(doReplaceURL); + }; + } + + router.didTransition = function(infos) { + emberRouter.didTransition(infos); + }; + }, + + _serializeQueryParams: function(targetRouteName, queryParams) { + var groupedByUrlKey = {}; + + forEachQueryParam(this, targetRouteName, queryParams, function(key, value, qp) { + var urlKey = qp.urlKey; + if (!groupedByUrlKey[urlKey]) { + groupedByUrlKey[urlKey] = []; + } + groupedByUrlKey[urlKey].push({ + qp: qp, + value: value + }); + delete queryParams[key]; + }); + + for (var key in groupedByUrlKey) { + var qps = groupedByUrlKey[key]; + if (qps.length > 1) { + var qp0 = qps[0].qp, qp1=qps[1].qp; + Ember.assert(fmt("You're not allowed to have more than one controller property map to the same query param key, but both `%@` and `%@` map to `%@`. You can fix this by mapping one of the controller properties to a different query param key via the `as` config option, e.g. `%@: { as: 'other-%@' }`", [qp0.fprop, qp1.fprop, qp0.urlKey, qp0.prop, qp0.prop]), false); + } + var qp = qps[0].qp; + queryParams[qp.urlKey] = qp.route.serializeQueryParam(qps[0].value, qp.urlKey, qp.type); + } + }, + + _deserializeQueryParams: function(targetRouteName, queryParams) { + forEachQueryParam(this, targetRouteName, queryParams, function(key, value, qp) { + delete queryParams[key]; + queryParams[qp.prop] = qp.route.deserializeQueryParam(value, qp.urlKey, qp.type); + }); + }, + + _pruneDefaultQueryParamValues: function(targetRouteName, queryParams) { + var qps = this._queryParamsFor(targetRouteName); + for (var key in queryParams) { + var qp = qps.map[key]; + if (qp && qp.sdef === queryParams[key]) { + delete queryParams[key]; + } + } + }, + + _doTransition: function(_targetRouteName, models, _queryParams) { + var targetRouteName = _targetRouteName || getActiveTargetName(this.router); + Ember.assert("The route " + targetRouteName + " was not found", targetRouteName && this.router.hasRoute(targetRouteName)); + + var queryParams = {}; + merge(queryParams, _queryParams); + this._prepareQueryParams(targetRouteName, models, queryParams); + + var transitionArgs = routeArgs(targetRouteName, models, queryParams); + var transitionPromise = this.router.transitionTo.apply(this.router, transitionArgs); + + listenForTransitionErrors(transitionPromise); + + return transitionPromise; + }, + + _prepareQueryParams: function(targetRouteName, models, queryParams) { + this._hydrateUnsuppliedQueryParams(targetRouteName, models, queryParams); + this._serializeQueryParams(targetRouteName, queryParams); + this._pruneDefaultQueryParamValues(targetRouteName, queryParams); + }, + + /** + Returns a merged query params meta object for a given route. + Useful for asking a route what its known query params are. + */ + _queryParamsFor: function(leafRouteName) { + if (this._qpCache[leafRouteName]) { + return this._qpCache[leafRouteName]; + } + + var map = {}, qps = [], qpCache = this._qpCache[leafRouteName] = { + map: map, + qps: qps + }; + + var routerjs = this.router; + var recogHandlerInfos = routerjs.recognizer.handlersFor(leafRouteName); + + for (var i = 0, len = recogHandlerInfos.length; i < len; ++i) { + var recogHandler = recogHandlerInfos[i]; + var route = routerjs.getHandler(recogHandler.handler); + var qpMeta = get(route, '_qp'); + + if (!qpMeta) { continue; } + + merge(map, qpMeta.map); + qps.push.apply(qps, qpMeta.qps); + } + + return { + qps: qps, + map: map + }; + }, + + /* + becomeResolved: function(payload, resolvedContext) { + var params = this.serialize(resolvedContext); + + if (payload) { + this.stashResolvedModel(payload, resolvedContext); + payload.params = payload.params || {}; + payload.params[this.name] = params; + } + + return this.factory('resolved', { + context: resolvedContext, + name: this.name, + handler: this.handler, + params: params + }); + }, + */ + + _hydrateUnsuppliedQueryParams: function(leafRouteName, contexts, queryParams) { + var state = calculatePostTransitionState(this, leafRouteName, contexts); + var handlerInfos = state.handlerInfos; + var appCache = this._bucketCache; + + stashParamNames(this, handlerInfos); + + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var route = handlerInfos[i].handler; + var qpMeta = get(route, '_qp'); + + for (var j = 0, qpLen = qpMeta.qps.length; j < qpLen; ++j) { + var qp = qpMeta.qps[j]; + var presentProp = qp.prop in queryParams && qp.prop || + qp.fprop in queryParams && qp.fprop; + + if (presentProp) { + if (presentProp !== qp.fprop) { + queryParams[qp.fprop] = queryParams[presentProp]; + delete queryParams[presentProp]; + } + } else { + var controllerProto = qp.cProto; + var cacheMeta = get(controllerProto, '_cacheMeta'); + + var cacheKey = controllerProto._calculateCacheKey(qp.ctrl, cacheMeta[qp.prop].parts, state.params); + queryParams[qp.fprop] = appCache.lookup(cacheKey, qp.prop, qp.def); + } + } + } + }, + + _scheduleLoadingEvent: function(transition, originRoute) { + this._cancelLoadingEvent(); + this._loadingStateTimer = run.scheduleOnce('routerTransitions', this, '_fireLoadingEvent', transition, originRoute); + }, + + _fireLoadingEvent: function(transition, originRoute) { + if (!this.router.activeTransition) { + // Don't fire an event if we've since moved on from + // the transition that put us in a loading state. + return; + } + + transition.trigger(true, 'loading', transition, originRoute); + }, + + _cancelLoadingEvent: function () { + if (this._loadingStateTimer) { + run.cancel(this._loadingStateTimer); + } + this._loadingStateTimer = null; + } + }); + + /* + Helper function for iterating root-ward, starting + from (but not including) the provided `originRoute`. + + Returns true if the last callback fired requested + to bubble upward. + + @private + */ + function forEachRouteAbove(originRoute, transition, callback) { + var handlerInfos = transition.state.handlerInfos; + var originRouteFound = false; + var handlerInfo, route; + + for (var i = handlerInfos.length - 1; i >= 0; --i) { + handlerInfo = handlerInfos[i]; + route = handlerInfo.handler; + + if (!originRouteFound) { + if (originRoute === route) { + originRouteFound = true; + } + continue; + } + + if (callback(route, handlerInfos[i + 1].handler) !== true) { + return false; + } + } + return true; + } + + // These get invoked when an action bubbles above ApplicationRoute + // and are not meant to be overridable. + var defaultActionHandlers = { + + willResolveModel: function(transition, originRoute) { + originRoute.router._scheduleLoadingEvent(transition, originRoute); + }, + + error: function(error, transition, originRoute) { + // Attempt to find an appropriate error substate to enter. + var router = originRoute.router; + + var tryTopLevel = forEachRouteAbove(originRoute, transition, function(route, childRoute) { + var childErrorRouteName = findChildRouteName(route, childRoute, 'error'); + if (childErrorRouteName) { + router.intermediateTransitionTo(childErrorRouteName, error); + return; + } + return true; + }); + + if (tryTopLevel) { + // Check for top-level error state to enter. + if (routeHasBeenDefined(originRoute.router, 'application_error')) { + router.intermediateTransitionTo('application_error', error); + return; + } + } + + logError(error, 'Error while processing route: ' + transition.targetName); + }, + + loading: function(transition, originRoute) { + // Attempt to find an appropriate loading substate to enter. + var router = originRoute.router; + + var tryTopLevel = forEachRouteAbove(originRoute, transition, function(route, childRoute) { + var childLoadingRouteName = findChildRouteName(route, childRoute, 'loading'); + + if (childLoadingRouteName) { + router.intermediateTransitionTo(childLoadingRouteName); + return; + } + + // Don't bubble above pivot route. + if (transition.pivotHandler !== route) { + return true; + } + }); + + if (tryTopLevel) { + // Check for top-level loading state to enter. + if (routeHasBeenDefined(originRoute.router, 'application_loading')) { + router.intermediateTransitionTo('application_loading'); + return; + } + } + } + }; + + function logError(error, initialMessage) { + var errorArgs = []; + + if (initialMessage) { errorArgs.push(initialMessage); } + + if (error) { + if (error.message) { errorArgs.push(error.message); } + if (error.stack) { errorArgs.push(error.stack); } + + if (typeof error === "string") { errorArgs.push(error); } + } + + Ember.Logger.error.apply(this, errorArgs); + } + + function findChildRouteName(parentRoute, originatingChildRoute, name) { + var router = parentRoute.router; + var childName; + var targetChildRouteName = originatingChildRoute.routeName.split('.').pop(); + var namespace = parentRoute.routeName === 'application' ? '' : parentRoute.routeName + '.'; + + + // Second, try general loading state, e.g. 'loading' + childName = namespace + name; + if (routeHasBeenDefined(router, childName)) { + return childName; + } + } + + function routeHasBeenDefined(router, name) { + var container = router.container; + return router.hasRoute(name) && + (container.has('template:' + name) || container.has('route:' + name)); + } + + function triggerEvent(handlerInfos, ignoreFailure, args) { + var name = args.shift(); + + if (!handlerInfos) { + if (ignoreFailure) { return; } + throw new EmberError("Can't trigger action '" + name + "' because your app hasn't finished transitioning into its first route. To trigger an action on destination routes during a transition, you can call `.send()` on the `Transition` object passed to the `model/beforeModel/afterModel` hooks."); + } + + var eventWasHandled = false; + var handlerInfo, handler; + + for (var i = handlerInfos.length - 1; i >= 0; i--) { + handlerInfo = handlerInfos[i]; + handler = handlerInfo.handler; + + if (handler._actions && handler._actions[name]) { + if (handler._actions[name].apply(handler, args) === true) { + eventWasHandled = true; + } else { + return; + } + } + } + + if (defaultActionHandlers[name]) { + defaultActionHandlers[name].apply(null, args); + return; + } + + if (!eventWasHandled && !ignoreFailure) { + throw new EmberError("Nothing handled the action '" + name + "'. If you did handle the action, this error can be caused by returning true from an action handler in a controller, causing the action to bubble."); + } + } + + function calculatePostTransitionState(emberRouter, leafRouteName, contexts) { + var routerjs = emberRouter.router; + var state = routerjs.applyIntent(leafRouteName, contexts); + var handlerInfos = state.handlerInfos; + var params = state.params; + + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var handlerInfo = handlerInfos[i]; + if (!handlerInfo.isResolved) { + handlerInfo = handlerInfo.becomeResolved(null, handlerInfo.context); + } + params[handlerInfo.name] = handlerInfo.params; + } + return state; + } + + function updatePaths(router) { + var appController = router.container.lookup('controller:application'); + + if (!appController) { + // appController might not exist when top-level loading/error + // substates have been entered since ApplicationRoute hasn't + // actually been entered at that point. + return; + } + + var infos = router.router.currentHandlerInfos; + var path = EmberRouter._routePath(infos); + + if (!('currentPath' in appController)) { + defineProperty(appController, 'currentPath'); + } + + set(appController, 'currentPath', path); + + if (!('currentRouteName' in appController)) { + defineProperty(appController, 'currentRouteName'); + } + + set(appController, 'currentRouteName', infos[infos.length - 1].name); + } + + EmberRouter.reopenClass({ + router: null, + + /** + The `Router.map` function allows you to define mappings from URLs to routes + and resources in your application. These mappings are defined within the + supplied callback function using `this.resource` and `this.route`. + + ```javascript + App.Router.map(function({ + this.route('about'); + this.resource('article'); + })); + ``` + + For more detailed examples please see + [the guides](http://emberjs.com/guides/routing/defining-your-routes/). + + @method map + @param callback + */ + map: function(callback) { + var router = this.router; + if (!router) { + router = new Router(); + + + router._triggerWillChangeContext = Ember.K; + router._triggerWillLeave = Ember.K; + + + router.callbacks = []; + router.triggerEvent = triggerEvent; + this.reopenClass({ router: router }); + } + + var dsl = EmberRouterDSL.map(function() { + this.resource('application', { path: "/" }, function() { + for (var i=0; i < router.callbacks.length; i++) { + router.callbacks[i].call(this); + } + callback.call(this); + }); + }); + + router.callbacks.push(callback); + router.map(dsl.generate()); + return router; + }, + + _routePath: function(handlerInfos) { + var path = []; + + // We have to handle coalescing resource names that + // are prefixed with their parent's names, e.g. + // ['foo', 'foo.bar.baz'] => 'foo.bar.baz', not 'foo.foo.bar.baz' + + function intersectionMatches(a1, a2) { + for (var i = 0, len = a1.length; i < len; ++i) { + if (a1[i] !== a2[i]) { + return false; + } + } + return true; + } + + var name, nameParts, oldNameParts; + for (var i=1, l=handlerInfos.length; i 0) - (diff < 0); + } + + /** + This will compare two javascript values of possibly different types. + It will tell you which one is greater than the other by returning: + + - -1 if the first is smaller than the second, + - 0 if both are equal, + - 1 if the first is greater than the second. + + The order is calculated based on `Ember.ORDER_DEFINITION`, if types are different. + In case they have the same type an appropriate comparison for this type is made. + + ```javascript + Ember.compare('hello', 'hello'); // 0 + Ember.compare('abc', 'dfg'); // -1 + Ember.compare(2, 1); // 1 + ``` + + @method compare + @for Ember + @param {Object} v First value to compare + @param {Object} w Second value to compare + @return {Number} -1 if v < w, 0 if v = w and 1 if v > w. + */ + __exports__["default"] = function compare(v, w) { + if (v === w) { + return 0; + } + + var type1 = typeOf(v); + var type2 = typeOf(w); + + if (Comparable) { + if (type1 ==='instance' && Comparable.detect(v.constructor)) { + return v.constructor.compare(v, w); + } + + if (type2 === 'instance' && Comparable.detect(w.constructor)) { + return 1 - w.constructor.compare(w, v); + } + } + + var res = spaceship(TYPE_ORDER[type1], TYPE_ORDER[type2]); + if (res !== 0) { + return res; + } + + // types are equal - so we have to check values now + switch (type1) { + case 'boolean': + case 'number': + return spaceship(v,w); + + case 'string': + return spaceship(v.localeCompare(w), 0); + + case 'array': + var vLen = v.length; + var wLen = w.length; + var len = Math.min(vLen, wLen); + + for (var i = 0; i < len; i++) { + var r = compare(v[i], w[i]); + if (r !== 0) { + return r; + } + } + + // all elements are equal now + // shorter array should be ordered first + return spaceship(vLen, wLen); + + case 'instance': + if (Comparable && Comparable.detect(v)) { + return v.compare(v, w); + } + return 0; + + case 'date': + return spaceship(v.getTime(), w.getTime()); + + default: + return 0; + } + } + }); +enifed("ember-runtime/computed/array_computed", + ["ember-metal/core","ember-runtime/computed/reduce_computed","ember-metal/enumerable_utils","ember-metal/platform","ember-metal/observer","ember-metal/error","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var reduceComputed = __dependency2__.reduceComputed; + var ReduceComputedProperty = __dependency2__.ReduceComputedProperty; + var forEach = __dependency3__.forEach; + var o_create = __dependency4__.create; + var addObserver = __dependency5__.addObserver; + var EmberError = __dependency6__["default"]; + + var a_slice = [].slice; + + function ArrayComputedProperty() { + var cp = this; + + ReduceComputedProperty.apply(this, arguments); + + this.func = (function(reduceFunc) { + return function (propertyName) { + if (!cp._hasInstanceMeta(this, propertyName)) { + // When we recompute an array computed property, we need already + // retrieved arrays to be updated; we can't simply empty the cache and + // hope the array is re-retrieved. + forEach(cp._dependentKeys, function(dependentKey) { + addObserver(this, dependentKey, function() { + cp.recomputeOnce.call(this, propertyName); + }); + }, this); + } + + return reduceFunc.apply(this, arguments); + }; + })(this.func); + + return this; + } + + ArrayComputedProperty.prototype = o_create(ReduceComputedProperty.prototype); + + ArrayComputedProperty.prototype.initialValue = function () { + return Ember.A(); + }; + + ArrayComputedProperty.prototype.resetValue = function (array) { + array.clear(); + return array; + }; + + // This is a stopgap to keep the reference counts correct with lazy CPs. + ArrayComputedProperty.prototype.didChange = function (obj, keyName) { + return; + }; + + /** + Creates a computed property which operates on dependent arrays and + is updated with "one at a time" semantics. When items are added or + removed from the dependent array(s) an array computed only operates + on the change instead of re-evaluating the entire array. This should + return an array, if you'd like to use "one at a time" semantics and + compute some value other then an array look at + `Ember.reduceComputed`. + + If there are more than one arguments the first arguments are + considered to be dependent property keys. The last argument is + required to be an options object. The options object can have the + following three properties. + + `initialize` - An optional initialize function. Typically this will be used + to set up state on the instanceMeta object. + + `removedItem` - A function that is called each time an element is + removed from the array. + + `addedItem` - A function that is called each time an element is + added to the array. + + + The `initialize` function has the following signature: + + ```javascript + function(array, changeMeta, instanceMeta) + ``` + + `array` - The initial value of the arrayComputed, an empty array. + + `changeMeta` - An object which contains meta information about the + computed. It contains the following properties: + + - `property` the computed property + - `propertyName` the name of the property on the object + + `instanceMeta` - An object that can be used to store meta + information needed for calculating your computed. For example a + unique computed might use this to store the number of times a given + element is found in the dependent array. + + + The `removedItem` and `addedItem` functions both have the following signature: + + ```javascript + function(accumulatedValue, item, changeMeta, instanceMeta) + ``` + + `accumulatedValue` - The value returned from the last time + `removedItem` or `addedItem` was called or an empty array. + + `item` - the element added or removed from the array + + `changeMeta` - An object which contains meta information about the + change. It contains the following properties: + + - `property` the computed property + - `propertyName` the name of the property on the object + - `index` the index of the added or removed item + - `item` the added or removed item: this is exactly the same as + the second arg + - `arrayChanged` the array that triggered the change. Can be + useful when depending on multiple arrays. + + For property changes triggered on an item property change (when + depKey is something like `someArray.@each.someProperty`), + `changeMeta` will also contain the following property: + + - `previousValues` an object whose keys are the properties that changed on + the item, and whose values are the item's previous values. + + `previousValues` is important Ember coalesces item property changes via + Ember.run.once. This means that by the time removedItem gets called, item has + the new values, but you may need the previous value (eg for sorting & + filtering). + + `instanceMeta` - An object that can be used to store meta + information needed for calculating your computed. For example a + unique computed might use this to store the number of times a given + element is found in the dependent array. + + The `removedItem` and `addedItem` functions should return the accumulated + value. It is acceptable to not return anything (ie return undefined) + to invalidate the computation. This is generally not a good idea for + arrayComputed but it's used in eg max and min. + + Example + + ```javascript + Ember.computed.map = function(dependentKey, callback) { + var options = { + addedItem: function(array, item, changeMeta, instanceMeta) { + var mapped = callback(item); + array.insertAt(changeMeta.index, mapped); + return array; + }, + removedItem: function(array, item, changeMeta, instanceMeta) { + array.removeAt(changeMeta.index, 1); + return array; + } + }; + + return Ember.arrayComputed(dependentKey, options); + }; + ``` + + @method arrayComputed + @for Ember + @param {String} [dependentKeys*] + @param {Object} options + @return {Ember.ComputedProperty} + */ + function arrayComputed (options) { + var args; + + if (arguments.length > 1) { + args = a_slice.call(arguments, 0, -1); + options = a_slice.call(arguments, -1)[0]; + } + + if (typeof options !== 'object') { + throw new EmberError('Array Computed Property declared without an options hash'); + } + + var cp = new ArrayComputedProperty(options); + + if (args) { + cp.property.apply(cp, args); + } + + return cp; + } + + __exports__.arrayComputed = arrayComputed; + __exports__.ArrayComputedProperty = ArrayComputedProperty; + }); +enifed("ember-runtime/computed/reduce_computed", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/error","ember-metal/property_events","ember-metal/expand_properties","ember-metal/observer","ember-metal/computed","ember-metal/platform","ember-metal/enumerable_utils","ember-runtime/system/tracked_array","ember-runtime/mixins/array","ember-metal/run_loop","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert + var e_get = __dependency2__.get; + var set = __dependency3__.set; + var guidFor = __dependency4__.guidFor; + var metaFor = __dependency4__.meta; + var EmberError = __dependency5__["default"]; + var propertyWillChange = __dependency6__.propertyWillChange; + var propertyDidChange = __dependency6__.propertyDidChange; + var expandProperties = __dependency7__["default"]; + var addObserver = __dependency8__.addObserver; + var observersFor = __dependency8__.observersFor; + var removeObserver = __dependency8__.removeObserver; + var addBeforeObserver = __dependency8__.addBeforeObserver; + var removeBeforeObserver = __dependency8__.removeBeforeObserver; + var ComputedProperty = __dependency9__.ComputedProperty; + var cacheFor = __dependency9__.cacheFor; + var o_create = __dependency10__.create; + var forEach = __dependency11__.forEach; + var TrackedArray = __dependency12__["default"]; + var EmberArray = __dependency13__["default"]; + var run = __dependency14__["default"]; + var isArray = __dependency4__.isArray; + + var cacheSet = cacheFor.set; + var cacheGet = cacheFor.get; + var cacheRemove = cacheFor.remove; + var a_slice = [].slice; + // Here we explicitly don't allow `@each.foo`; it would require some special + // testing, but there's no particular reason why it should be disallowed. + var eachPropertyPattern = /^(.*)\.@each\.(.*)/; + var doubleEachPropertyPattern = /(.*\.@each){2,}/; + var arrayBracketPattern = /\.\[\]$/; + + function get(obj, key) { + if (key === '@this') { + return obj; + } + + return e_get(obj, key); + } + + /* + Tracks changes to dependent arrays, as well as to properties of items in + dependent arrays. + + @class DependentArraysObserver + */ + function DependentArraysObserver(callbacks, cp, instanceMeta, context, propertyName, sugarMeta) { + // user specified callbacks for `addedItem` and `removedItem` + this.callbacks = callbacks; + + // the computed property: remember these are shared across instances + this.cp = cp; + + // the ReduceComputedPropertyInstanceMeta this DependentArraysObserver is + // associated with + this.instanceMeta = instanceMeta; + + // A map of array guids to dependentKeys, for the given context. We track + // this because we want to set up the computed property potentially before the + // dependent array even exists, but when the array observer fires, we lack + // enough context to know what to update: we can recover that context by + // getting the dependentKey. + this.dependentKeysByGuid = {}; + + // a map of dependent array guids -> TrackedArray instances. We use + // this to lazily recompute indexes for item property observers. + this.trackedArraysByGuid = {}; + + // We suspend observers to ignore replacements from `reset` when totally + // recomputing. Unfortunately we cannot properly suspend the observers + // because we only have the key; instead we make the observers no-ops + this.suspended = false; + + // This is used to coalesce item changes from property observers within a + // single item. + this.changedItems = {}; + // This is used to coalesce item changes for multiple items that depend on + // some shared state. + this.changedItemCount = 0; + } + + function ItemPropertyObserverContext (dependentArray, index, trackedArray) { + Ember.assert('Internal error: trackedArray is null or undefined', trackedArray); + + this.dependentArray = dependentArray; + this.index = index; + this.item = dependentArray.objectAt(index); + this.trackedArray = trackedArray; + this.beforeObserver = null; + this.observer = null; + this.destroyed = false; + } + + DependentArraysObserver.prototype = { + setValue: function (newValue) { + this.instanceMeta.setValue(newValue, true); + }, + + getValue: function () { + return this.instanceMeta.getValue(); + }, + + setupObservers: function (dependentArray, dependentKey) { + this.dependentKeysByGuid[guidFor(dependentArray)] = dependentKey; + + dependentArray.addArrayObserver(this, { + willChange: 'dependentArrayWillChange', + didChange: 'dependentArrayDidChange' + }); + + if (this.cp._itemPropertyKeys[dependentKey]) { + this.setupPropertyObservers(dependentKey, this.cp._itemPropertyKeys[dependentKey]); + } + }, + + teardownObservers: function (dependentArray, dependentKey) { + var itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey] || []; + + delete this.dependentKeysByGuid[guidFor(dependentArray)]; + + this.teardownPropertyObservers(dependentKey, itemPropertyKeys); + + dependentArray.removeArrayObserver(this, { + willChange: 'dependentArrayWillChange', + didChange: 'dependentArrayDidChange' + }); + }, + + suspendArrayObservers: function (callback, binding) { + var oldSuspended = this.suspended; + this.suspended = true; + callback.call(binding); + this.suspended = oldSuspended; + }, + + setupPropertyObservers: function (dependentKey, itemPropertyKeys) { + var dependentArray = get(this.instanceMeta.context, dependentKey); + var length = get(dependentArray, 'length'); + var observerContexts = new Array(length); + + this.resetTransformations(dependentKey, observerContexts); + + forEach(dependentArray, function (item, index) { + var observerContext = this.createPropertyObserverContext(dependentArray, index, this.trackedArraysByGuid[dependentKey]); + observerContexts[index] = observerContext; + + forEach(itemPropertyKeys, function (propertyKey) { + addBeforeObserver(item, propertyKey, this, observerContext.beforeObserver); + addObserver(item, propertyKey, this, observerContext.observer); + }, this); + }, this); + }, + + teardownPropertyObservers: function (dependentKey, itemPropertyKeys) { + var dependentArrayObserver = this; + var trackedArray = this.trackedArraysByGuid[dependentKey]; + var beforeObserver, observer, item; + + if (!trackedArray) { return; } + + trackedArray.apply(function (observerContexts, offset, operation) { + if (operation === TrackedArray.DELETE) { return; } + + forEach(observerContexts, function (observerContext) { + observerContext.destroyed = true; + beforeObserver = observerContext.beforeObserver; + observer = observerContext.observer; + item = observerContext.item; + + forEach(itemPropertyKeys, function (propertyKey) { + removeBeforeObserver(item, propertyKey, dependentArrayObserver, beforeObserver); + removeObserver(item, propertyKey, dependentArrayObserver, observer); + }); + }); + }); + }, + + createPropertyObserverContext: function (dependentArray, index, trackedArray) { + var observerContext = new ItemPropertyObserverContext(dependentArray, index, trackedArray); + + this.createPropertyObserver(observerContext); + + return observerContext; + }, + + createPropertyObserver: function (observerContext) { + var dependentArrayObserver = this; + + observerContext.beforeObserver = function (obj, keyName) { + return dependentArrayObserver.itemPropertyWillChange(obj, keyName, observerContext.dependentArray, observerContext); + }; + + observerContext.observer = function (obj, keyName) { + return dependentArrayObserver.itemPropertyDidChange(obj, keyName, observerContext.dependentArray, observerContext); + }; + }, + + resetTransformations: function (dependentKey, observerContexts) { + this.trackedArraysByGuid[dependentKey] = new TrackedArray(observerContexts); + }, + + trackAdd: function (dependentKey, index, newItems) { + var trackedArray = this.trackedArraysByGuid[dependentKey]; + + if (trackedArray) { + trackedArray.addItems(index, newItems); + } + }, + + trackRemove: function (dependentKey, index, removedCount) { + var trackedArray = this.trackedArraysByGuid[dependentKey]; + + if (trackedArray) { + return trackedArray.removeItems(index, removedCount); + } + + return []; + }, + + updateIndexes: function (trackedArray, array) { + var length = get(array, 'length'); + // OPTIMIZE: we could stop updating once we hit the object whose observer + // fired; ie partially apply the transformations + trackedArray.apply(function (observerContexts, offset, operation, operationIndex) { + // we don't even have observer contexts for removed items, even if we did, + // they no longer have any index in the array + if (operation === TrackedArray.DELETE) { return; } + if (operationIndex === 0 && operation === TrackedArray.RETAIN && observerContexts.length === length && offset === 0) { + // If we update many items we don't want to walk the array each time: we + // only need to update the indexes at most once per run loop. + return; + } + + forEach(observerContexts, function (context, index) { + context.index = index + offset; + }); + }); + }, + + dependentArrayWillChange: function (dependentArray, index, removedCount, addedCount) { + if (this.suspended) { return; } + + var removedItem = this.callbacks.removedItem; + var changeMeta; + var guid = guidFor(dependentArray); + var dependentKey = this.dependentKeysByGuid[guid]; + var itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey] || []; + var length = get(dependentArray, 'length'); + var normalizedIndex = normalizeIndex(index, length, 0); + var normalizedRemoveCount = normalizeRemoveCount(normalizedIndex, length, removedCount); + var item, itemIndex, sliceIndex, observerContexts; + + observerContexts = this.trackRemove(dependentKey, normalizedIndex, normalizedRemoveCount); + + function removeObservers(propertyKey) { + observerContexts[sliceIndex].destroyed = true; + removeBeforeObserver(item, propertyKey, this, observerContexts[sliceIndex].beforeObserver); + removeObserver(item, propertyKey, this, observerContexts[sliceIndex].observer); + } + + for (sliceIndex = normalizedRemoveCount - 1; sliceIndex >= 0; --sliceIndex) { + itemIndex = normalizedIndex + sliceIndex; + if (itemIndex >= length) { break; } + + item = dependentArray.objectAt(itemIndex); + + forEach(itemPropertyKeys, removeObservers, this); + + changeMeta = new ChangeMeta(dependentArray, item, itemIndex, this.instanceMeta.propertyName, this.cp, normalizedRemoveCount); + this.setValue(removedItem.call( + this.instanceMeta.context, this.getValue(), item, changeMeta, this.instanceMeta.sugarMeta)); + } + this.callbacks.flushedChanges.call(this.instanceMeta.context, this.getValue(), this.instanceMeta.sugarMeta); + }, + + dependentArrayDidChange: function (dependentArray, index, removedCount, addedCount) { + if (this.suspended) { return; } + + var addedItem = this.callbacks.addedItem; + var guid = guidFor(dependentArray); + var dependentKey = this.dependentKeysByGuid[guid]; + var observerContexts = new Array(addedCount); + var itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey]; + var length = get(dependentArray, 'length'); + var normalizedIndex = normalizeIndex(index, length, addedCount); + var endIndex = normalizedIndex + addedCount; + var changeMeta, observerContext; + + forEach(dependentArray.slice(normalizedIndex, endIndex), function (item, sliceIndex) { + if (itemPropertyKeys) { + observerContext = this.createPropertyObserverContext(dependentArray, normalizedIndex + sliceIndex, + this.trackedArraysByGuid[dependentKey]); + observerContexts[sliceIndex] = observerContext; + + forEach(itemPropertyKeys, function (propertyKey) { + addBeforeObserver(item, propertyKey, this, observerContext.beforeObserver); + addObserver(item, propertyKey, this, observerContext.observer); + }, this); + } + + changeMeta = new ChangeMeta(dependentArray, item, normalizedIndex + sliceIndex, this.instanceMeta.propertyName, this.cp, addedCount); + this.setValue(addedItem.call( + this.instanceMeta.context, this.getValue(), item, changeMeta, this.instanceMeta.sugarMeta)); + }, this); + this.callbacks.flushedChanges.call(this.instanceMeta.context, this.getValue(), this.instanceMeta.sugarMeta); + this.trackAdd(dependentKey, normalizedIndex, observerContexts); + }, + + itemPropertyWillChange: function (obj, keyName, array, observerContext) { + var guid = guidFor(obj); + + if (!this.changedItems[guid]) { + this.changedItems[guid] = { + array: array, + observerContext: observerContext, + obj: obj, + previousValues: {} + }; + } + + ++this.changedItemCount; + this.changedItems[guid].previousValues[keyName] = get(obj, keyName); + }, + + itemPropertyDidChange: function (obj, keyName, array, observerContext) { + if (--this.changedItemCount === 0) { + this.flushChanges(); + } + }, + + flushChanges: function () { + var changedItems = this.changedItems; + var key, c, changeMeta; + + for (key in changedItems) { + c = changedItems[key]; + if (c.observerContext.destroyed) { continue; } + + this.updateIndexes(c.observerContext.trackedArray, c.observerContext.dependentArray); + + changeMeta = new ChangeMeta(c.array, c.obj, c.observerContext.index, this.instanceMeta.propertyName, this.cp, changedItems.length, c.previousValues); + this.setValue( + this.callbacks.removedItem.call(this.instanceMeta.context, this.getValue(), c.obj, changeMeta, this.instanceMeta.sugarMeta)); + this.setValue( + this.callbacks.addedItem.call(this.instanceMeta.context, this.getValue(), c.obj, changeMeta, this.instanceMeta.sugarMeta)); + } + + this.changedItems = {}; + this.callbacks.flushedChanges.call(this.instanceMeta.context, this.getValue(), this.instanceMeta.sugarMeta); + } + }; + + function normalizeIndex(index, length, newItemsOffset) { + if (index < 0) { + return Math.max(0, length + index); + } else if (index < length) { + return index; + } else /* index > length */ { + return Math.min(length - newItemsOffset, index); + } + } + + function normalizeRemoveCount(index, length, removedCount) { + return Math.min(removedCount, length - index); + } + + function ChangeMeta(dependentArray, item, index, propertyName, property, changedCount, previousValues){ + this.arrayChanged = dependentArray; + this.index = index; + this.item = item; + this.propertyName = propertyName; + this.property = property; + this.changedCount = changedCount; + + if (previousValues) { + // previous values only available for item property changes + this.previousValues = previousValues; + } + } + + function addItems(dependentArray, callbacks, cp, propertyName, meta) { + forEach(dependentArray, function (item, index) { + meta.setValue( callbacks.addedItem.call( + this, meta.getValue(), item, new ChangeMeta(dependentArray, item, index, propertyName, cp, dependentArray.length), meta.sugarMeta)); + }, this); + callbacks.flushedChanges.call(this, meta.getValue(), meta.sugarMeta); + } + + function reset(cp, propertyName) { + var callbacks = cp._callbacks(); + var hadMeta = cp._hasInstanceMeta(this, propertyName); + var meta = cp._instanceMeta(this, propertyName); + + if (hadMeta) { meta.setValue(cp.resetValue(meta.getValue())); } + + if (cp.options.initialize) { + cp.options.initialize.call(this, meta.getValue(), { + property: cp, + propertyName: propertyName + }, meta.sugarMeta); + } + } + + function partiallyRecomputeFor(obj, dependentKey) { + if (arrayBracketPattern.test(dependentKey)) { + return false; + } + + var value = get(obj, dependentKey); + return EmberArray.detect(value); + } + + function ReduceComputedPropertyInstanceMeta(context, propertyName, initialValue) { + this.context = context; + this.propertyName = propertyName; + this.cache = metaFor(context).cache; + this.dependentArrays = {}; + this.sugarMeta = {}; + this.initialValue = initialValue; + } + + ReduceComputedPropertyInstanceMeta.prototype = { + getValue: function () { + var value = cacheGet(this.cache, this.propertyName); + + if (value !== undefined) { + return value; + } else { + return this.initialValue; + } + }, + + setValue: function(newValue, triggerObservers) { + // This lets sugars force a recomputation, handy for very simple + // implementations of eg max. + if (newValue === cacheGet(this.cache, this.propertyName)) { + return; + } + + if (triggerObservers) { + propertyWillChange(this.context, this.propertyName); + } + + if (newValue === undefined) { + cacheRemove(this.cache, this.propertyName); + } else { + cacheSet(this.cache, this.propertyName, newValue); + } + + if (triggerObservers) { + propertyDidChange(this.context, this.propertyName); + } + } + }; + + /** + A computed property whose dependent keys are arrays and which is updated with + "one at a time" semantics. + + @class ReduceComputedProperty + @namespace Ember + @extends Ember.ComputedProperty + @constructor + */ + + __exports__.ReduceComputedProperty = ReduceComputedProperty; + // TODO: default export + + function ReduceComputedProperty(options) { + var cp = this; + + this.options = options; + this._dependentKeys = null; + // A map of dependentKey -> [itemProperty, ...] that tracks what properties of + // items in the array we must track to update this property. + this._itemPropertyKeys = {}; + this._previousItemPropertyKeys = {}; + + this.readOnly(); + this.cacheable(); + + this.recomputeOnce = function(propertyName) { + // What we really want to do is coalesce by . + // We need a form of `scheduleOnce` that accepts an arbitrary token to + // coalesce by, in addition to the target and method. + run.once(this, recompute, propertyName); + }; + + var recompute = function(propertyName) { + var dependentKeys = cp._dependentKeys; + var meta = cp._instanceMeta(this, propertyName); + var callbacks = cp._callbacks(); + + reset.call(this, cp, propertyName); + + meta.dependentArraysObserver.suspendArrayObservers(function () { + forEach(cp._dependentKeys, function (dependentKey) { + Ember.assert( + 'dependent array ' + dependentKey + ' must be an `Ember.Array`. ' + + 'If you are not extending arrays, you will need to wrap native arrays with `Ember.A`', + !(isArray(get(this, dependentKey)) && !EmberArray.detect(get(this, dependentKey)))); + + if (!partiallyRecomputeFor(this, dependentKey)) { return; } + + var dependentArray = get(this, dependentKey); + var previousDependentArray = meta.dependentArrays[dependentKey]; + + if (dependentArray === previousDependentArray) { + // The array may be the same, but our item property keys may have + // changed, so we set them up again. We can't easily tell if they've + // changed: the array may be the same object, but with different + // contents. + if (cp._previousItemPropertyKeys[dependentKey]) { + delete cp._previousItemPropertyKeys[dependentKey]; + meta.dependentArraysObserver.setupPropertyObservers(dependentKey, cp._itemPropertyKeys[dependentKey]); + } + } else { + meta.dependentArrays[dependentKey] = dependentArray; + + if (previousDependentArray) { + meta.dependentArraysObserver.teardownObservers(previousDependentArray, dependentKey); + } + + if (dependentArray) { + meta.dependentArraysObserver.setupObservers(dependentArray, dependentKey); + } + } + }, this); + }, this); + + forEach(cp._dependentKeys, function(dependentKey) { + if (!partiallyRecomputeFor(this, dependentKey)) { return; } + + var dependentArray = get(this, dependentKey); + + if (dependentArray) { + addItems.call(this, dependentArray, callbacks, cp, propertyName, meta); + } + }, this); + }; + + + this.func = function (propertyName) { + Ember.assert('Computed reduce values require at least one dependent key', cp._dependentKeys); + + recompute.call(this, propertyName); + + return cp._instanceMeta(this, propertyName).getValue(); + }; + } + + ReduceComputedProperty.prototype = o_create(ComputedProperty.prototype); + + function defaultCallback(computedValue) { + return computedValue; + } + + ReduceComputedProperty.prototype._callbacks = function () { + if (!this.callbacks) { + var options = this.options; + + this.callbacks = { + removedItem: options.removedItem || defaultCallback, + addedItem: options.addedItem || defaultCallback, + flushedChanges: options.flushedChanges || defaultCallback + }; + } + + return this.callbacks; + }; + + ReduceComputedProperty.prototype._hasInstanceMeta = function (context, propertyName) { + return !!metaFor(context).cacheMeta[propertyName]; + }; + + ReduceComputedProperty.prototype._instanceMeta = function (context, propertyName) { + var cacheMeta = metaFor(context).cacheMeta; + var meta = cacheMeta[propertyName]; + + if (!meta) { + meta = cacheMeta[propertyName] = new ReduceComputedPropertyInstanceMeta(context, propertyName, this.initialValue()); + meta.dependentArraysObserver = new DependentArraysObserver(this._callbacks(), this, meta, context, propertyName, meta.sugarMeta); + } + + return meta; + }; + + ReduceComputedProperty.prototype.initialValue = function () { + if (typeof this.options.initialValue === 'function') { + return this.options.initialValue(); + } + else { + return this.options.initialValue; + } + }; + + ReduceComputedProperty.prototype.resetValue = function (value) { + return this.initialValue(); + }; + + ReduceComputedProperty.prototype.itemPropertyKey = function (dependentArrayKey, itemPropertyKey) { + this._itemPropertyKeys[dependentArrayKey] = this._itemPropertyKeys[dependentArrayKey] || []; + this._itemPropertyKeys[dependentArrayKey].push(itemPropertyKey); + }; + + ReduceComputedProperty.prototype.clearItemPropertyKeys = function (dependentArrayKey) { + if (this._itemPropertyKeys[dependentArrayKey]) { + this._previousItemPropertyKeys[dependentArrayKey] = this._itemPropertyKeys[dependentArrayKey]; + this._itemPropertyKeys[dependentArrayKey] = []; + } + }; + + ReduceComputedProperty.prototype.property = function () { + var cp = this; + var args = a_slice.call(arguments); + var propertyArgs = {}; + var match, dependentArrayKey, itemPropertyKey; + + forEach(args, function (dependentKey) { + if (doubleEachPropertyPattern.test(dependentKey)) { + throw new EmberError('Nested @each properties not supported: ' + dependentKey); + } else if (match = eachPropertyPattern.exec(dependentKey)) { + dependentArrayKey = match[1]; + + var itemPropertyKeyPattern = match[2]; + var addItemPropertyKey = function (itemPropertyKey) { + cp.itemPropertyKey(dependentArrayKey, itemPropertyKey); + }; + + expandProperties(itemPropertyKeyPattern, addItemPropertyKey); + propertyArgs[guidFor(dependentArrayKey)] = dependentArrayKey; + } else { + propertyArgs[guidFor(dependentKey)] = dependentKey; + } + }); + + var propertyArgsToArray = []; + for (var guid in propertyArgs) { + propertyArgsToArray.push(propertyArgs[guid]); + } + + return ComputedProperty.prototype.property.apply(this, propertyArgsToArray); + }; + + /** + Creates a computed property which operates on dependent arrays and + is updated with "one at a time" semantics. When items are added or + removed from the dependent array(s) a reduce computed only operates + on the change instead of re-evaluating the entire array. + + If there are more than one arguments the first arguments are + considered to be dependent property keys. The last argument is + required to be an options object. The options object can have the + following four properties: + + `initialValue` - A value or function that will be used as the initial + value for the computed. If this property is a function the result of calling + the function will be used as the initial value. This property is required. + + `initialize` - An optional initialize function. Typically this will be used + to set up state on the instanceMeta object. + + `removedItem` - A function that is called each time an element is removed + from the array. + + `addedItem` - A function that is called each time an element is added to + the array. + + + The `initialize` function has the following signature: + + ```javascript + function(initialValue, changeMeta, instanceMeta) + ``` + + `initialValue` - The value of the `initialValue` property from the + options object. + + `changeMeta` - An object which contains meta information about the + computed. It contains the following properties: + + - `property` the computed property + - `propertyName` the name of the property on the object + + `instanceMeta` - An object that can be used to store meta + information needed for calculating your computed. For example a + unique computed might use this to store the number of times a given + element is found in the dependent array. + + + The `removedItem` and `addedItem` functions both have the following signature: + + ```javascript + function(accumulatedValue, item, changeMeta, instanceMeta) + ``` + + `accumulatedValue` - The value returned from the last time + `removedItem` or `addedItem` was called or `initialValue`. + + `item` - the element added or removed from the array + + `changeMeta` - An object which contains meta information about the + change. It contains the following properties: + + - `property` the computed property + - `propertyName` the name of the property on the object + - `index` the index of the added or removed item + - `item` the added or removed item: this is exactly the same as + the second arg + - `arrayChanged` the array that triggered the change. Can be + useful when depending on multiple arrays. + + For property changes triggered on an item property change (when + depKey is something like `someArray.@each.someProperty`), + `changeMeta` will also contain the following property: + + - `previousValues` an object whose keys are the properties that changed on + the item, and whose values are the item's previous values. + + `previousValues` is important Ember coalesces item property changes via + Ember.run.once. This means that by the time removedItem gets called, item has + the new values, but you may need the previous value (eg for sorting & + filtering). + + `instanceMeta` - An object that can be used to store meta + information needed for calculating your computed. For example a + unique computed might use this to store the number of times a given + element is found in the dependent array. + + The `removedItem` and `addedItem` functions should return the accumulated + value. It is acceptable to not return anything (ie return undefined) + to invalidate the computation. This is generally not a good idea for + arrayComputed but it's used in eg max and min. + + Note that observers will be fired if either of these functions return a value + that differs from the accumulated value. When returning an object that + mutates in response to array changes, for example an array that maps + everything from some other array (see `Ember.computed.map`), it is usually + important that the *same* array be returned to avoid accidentally triggering observers. + + Example + + ```javascript + Ember.computed.max = function(dependentKey) { + return Ember.reduceComputed(dependentKey, { + initialValue: -Infinity, + + addedItem: function(accumulatedValue, item, changeMeta, instanceMeta) { + return Math.max(accumulatedValue, item); + }, + + removedItem: function(accumulatedValue, item, changeMeta, instanceMeta) { + if (item < accumulatedValue) { + return accumulatedValue; + } + } + }); + }; + ``` + + Dependent keys may refer to `@this` to observe changes to the object itself, + which must be array-like, rather than a property of the object. This is + mostly useful for array proxies, to ensure objects are retrieved via + `objectAtContent`. This is how you could sort items by properties defined on an item controller. + + Example + + ```javascript + App.PeopleController = Ember.ArrayController.extend({ + itemController: 'person', + + sortedPeople: Ember.computed.sort('@this.@each.reversedName', function(personA, personB) { + // `reversedName` isn't defined on Person, but we have access to it via + // the item controller App.PersonController. If we'd used + // `content.@each.reversedName` above, we would be getting the objects + // directly and not have access to `reversedName`. + // + var reversedNameA = get(personA, 'reversedName'); + var reversedNameB = get(personB, 'reversedName'); + + return Ember.compare(reversedNameA, reversedNameB); + }) + }); + + App.PersonController = Ember.ObjectController.extend({ + reversedName: function() { + return reverse(get(this, 'name')); + }.property('name') + }); + ``` + + Dependent keys whose values are not arrays are treated as regular + dependencies: when they change, the computed property is completely + recalculated. It is sometimes useful to have dependent arrays with similar + semantics. Dependent keys which end in `.[]` do not use "one at a time" + semantics. When an item is added or removed from such a dependency, the + computed property is completely recomputed. + + When the computed property is completely recomputed, the `accumulatedValue` + is discarded, it starts with `initialValue` again, and each item is passed + to `addedItem` in turn. + + Example + + ```javascript + Ember.Object.extend({ + // When `string` is changed, `computed` is completely recomputed. + string: 'a string', + + // When an item is added to `array`, `addedItem` is called. + array: [], + + // When an item is added to `anotherArray`, `computed` is completely + // recomputed. + anotherArray: [], + + computed: Ember.reduceComputed('string', 'array', 'anotherArray.[]', { + addedItem: addedItemCallback, + removedItem: removedItemCallback + }) + }); + ``` + + @method reduceComputed + @for Ember + @param {String} [dependentKeys*] + @param {Object} options + @return {Ember.ComputedProperty} + */ + function reduceComputed(options) { + var args; + + if (arguments.length > 1) { + args = a_slice.call(arguments, 0, -1); + options = a_slice.call(arguments, -1)[0]; + } + + if (typeof options !== 'object') { + throw new EmberError('Reduce Computed Property declared without an options hash'); + } + + if (!('initialValue' in options)) { + throw new EmberError('Reduce Computed Property declared without an initial value'); + } + + var cp = new ReduceComputedProperty(options); + + if (args) { + cp.property.apply(cp, args); + } + + return cp; + } + + __exports__.reduceComputed = reduceComputed; + }); +enifed("ember-runtime/computed/reduce_computed_macros", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/error","ember-metal/enumerable_utils","ember-metal/run_loop","ember-metal/observer","ember-runtime/computed/array_computed","ember-runtime/computed/reduce_computed","ember-runtime/system/subarray","ember-metal/keys","ember-runtime/compare","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + // Ember.assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var isArray = __dependency4__.isArray; + var guidFor = __dependency4__.guidFor; + var EmberError = __dependency5__["default"]; + var forEach = __dependency6__.forEach; + var run = __dependency7__["default"]; + var addObserver = __dependency8__.addObserver; + var arrayComputed = __dependency9__.arrayComputed; + var reduceComputed = __dependency10__.reduceComputed; + var SubArray = __dependency11__["default"]; + var keys = __dependency12__["default"]; + var compare = __dependency13__["default"]; + + var a_slice = [].slice; + + /** + A computed property that returns the sum of the value + in the dependent array. + + @method computed.sum + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computes the sum of all values in the dependentKey's array + @since 1.4.0 + */ + + function sum(dependentKey){ + return reduceComputed(dependentKey, { + initialValue: 0, + + addedItem: function(accumulatedValue, item, changeMeta, instanceMeta){ + return accumulatedValue + item; + }, + + removedItem: function(accumulatedValue, item, changeMeta, instanceMeta){ + return accumulatedValue - item; + } + }); + } + + __exports__.sum = sum;/** + A computed property that calculates the maximum value in the + dependent array. This will return `-Infinity` when the dependent + array is empty. + + ```javascript + var Person = Ember.Object.extend({ + childAges: Ember.computed.mapBy('children', 'age'), + maxChildAge: Ember.computed.max('childAges') + }); + + var lordByron = Person.create({ children: [] }); + + lordByron.get('maxChildAge'); // -Infinity + lordByron.get('children').pushObject({ + name: 'Augusta Ada Byron', age: 7 + }); + lordByron.get('maxChildAge'); // 7 + lordByron.get('children').pushObjects([{ + name: 'Allegra Byron', + age: 5 + }, { + name: 'Elizabeth Medora Leigh', + age: 8 + }]); + lordByron.get('maxChildAge'); // 8 + ``` + + @method computed.max + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computes the largest value in the dependentKey's array + */ + function max(dependentKey) { + return reduceComputed(dependentKey, { + initialValue: -Infinity, + + addedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { + return Math.max(accumulatedValue, item); + }, + + removedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { + if (item < accumulatedValue) { + return accumulatedValue; + } + } + }); + } + + __exports__.max = max;/** + A computed property that calculates the minimum value in the + dependent array. This will return `Infinity` when the dependent + array is empty. + + ```javascript + var Person = Ember.Object.extend({ + childAges: Ember.computed.mapBy('children', 'age'), + minChildAge: Ember.computed.min('childAges') + }); + + var lordByron = Person.create({ children: [] }); + + lordByron.get('minChildAge'); // Infinity + lordByron.get('children').pushObject({ + name: 'Augusta Ada Byron', age: 7 + }); + lordByron.get('minChildAge'); // 7 + lordByron.get('children').pushObjects([{ + name: 'Allegra Byron', + age: 5 + }, { + name: 'Elizabeth Medora Leigh', + age: 8 + }]); + lordByron.get('minChildAge'); // 5 + ``` + + @method computed.min + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computes the smallest value in the dependentKey's array + */ + function min(dependentKey) { + return reduceComputed(dependentKey, { + initialValue: Infinity, + + addedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { + return Math.min(accumulatedValue, item); + }, + + removedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { + if (item > accumulatedValue) { + return accumulatedValue; + } + } + }); + } + + __exports__.min = min;/** + Returns an array mapped via the callback + + The callback method you provide should have the following signature. + `item` is the current item in the iteration. + `index` is the integer index of the current item in the iteration. + + ```javascript + function(item, index); + ``` + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + excitingChores: Ember.computed.map('chores', function(chore, index) { + return chore.toUpperCase() + '!'; + }) + }); + + var hamster = Hamster.create({ + chores: ['clean', 'write more unit tests'] + }); + + hamster.get('excitingChores'); // ['CLEAN!', 'WRITE MORE UNIT TESTS!'] + ``` + + @method computed.map + @for Ember + @param {String} dependentKey + @param {Function} callback + @return {Ember.ComputedProperty} an array mapped via the callback + */ + function map(dependentKey, callback) { + var options = { + addedItem: function(array, item, changeMeta, instanceMeta) { + var mapped = callback.call(this, item, changeMeta.index); + array.insertAt(changeMeta.index, mapped); + return array; + }, + removedItem: function(array, item, changeMeta, instanceMeta) { + array.removeAt(changeMeta.index, 1); + return array; + } + }; + + return arrayComputed(dependentKey, options); + } + + __exports__.map = map;/** + Returns an array mapped to the specified key. + + ```javascript + var Person = Ember.Object.extend({ + childAges: Ember.computed.mapBy('children', 'age') + }); + + var lordByron = Person.create({ children: [] }); + + lordByron.get('childAges'); // [] + lordByron.get('children').pushObject({ name: 'Augusta Ada Byron', age: 7 }); + lordByron.get('childAges'); // [7] + lordByron.get('children').pushObjects([{ + name: 'Allegra Byron', + age: 5 + }, { + name: 'Elizabeth Medora Leigh', + age: 8 + }]); + lordByron.get('childAges'); // [7, 5, 8] + ``` + + @method computed.mapBy + @for Ember + @param {String} dependentKey + @param {String} propertyKey + @return {Ember.ComputedProperty} an array mapped to the specified key + */ + function mapBy (dependentKey, propertyKey) { + var callback = function(item) { return get(item, propertyKey); }; + return map(dependentKey + '.@each.' + propertyKey, callback); + } + + __exports__.mapBy = mapBy;/** + @method computed.mapProperty + @for Ember + @deprecated Use `Ember.computed.mapBy` instead + @param dependentKey + @param propertyKey + */ + var mapProperty = mapBy; + __exports__.mapProperty = mapProperty; + /** + Filters the array by the callback. + + The callback method you provide should have the following signature. + `item` is the current item in the iteration. + `index` is the integer index of the current item in the iteration. + + ```javascript + function(item, index); + ``` + + ```javascript + var Hamster = Ember.Object.extend({ + remainingChores: Ember.computed.filter('chores', function(chore, index) { + return !chore.done; + }) + }); + + var hamster = Hamster.create({ + chores: [ + { name: 'cook', done: true }, + { name: 'clean', done: true }, + { name: 'write more unit tests', done: false } + ] + }); + + hamster.get('remainingChores'); // [{name: 'write more unit tests', done: false}] + ``` + + @method computed.filter + @for Ember + @param {String} dependentKey + @param {Function} callback + @return {Ember.ComputedProperty} the filtered array + */ + function filter(dependentKey, callback) { + var options = { + initialize: function (array, changeMeta, instanceMeta) { + instanceMeta.filteredArrayIndexes = new SubArray(); + }, + + addedItem: function (array, item, changeMeta, instanceMeta) { + var match = !!callback.call(this, item, changeMeta.index); + var filterIndex = instanceMeta.filteredArrayIndexes.addItem(changeMeta.index, match); + + if (match) { + array.insertAt(filterIndex, item); + } + + return array; + }, + + removedItem: function(array, item, changeMeta, instanceMeta) { + var filterIndex = instanceMeta.filteredArrayIndexes.removeItem(changeMeta.index); + + if (filterIndex > -1) { + array.removeAt(filterIndex); + } + + return array; + } + }; + + return arrayComputed(dependentKey, options); + } + + __exports__.filter = filter;/** + Filters the array by the property and value + + ```javascript + var Hamster = Ember.Object.extend({ + remainingChores: Ember.computed.filterBy('chores', 'done', false) + }); + + var hamster = Hamster.create({ + chores: [ + { name: 'cook', done: true }, + { name: 'clean', done: true }, + { name: 'write more unit tests', done: false } + ] + }); + + hamster.get('remainingChores'); // [{ name: 'write more unit tests', done: false }] + ``` + + @method computed.filterBy + @for Ember + @param {String} dependentKey + @param {String} propertyKey + @param {*} value + @return {Ember.ComputedProperty} the filtered array + */ + function filterBy (dependentKey, propertyKey, value) { + var callback; + + if (arguments.length === 2) { + callback = function(item) { + return get(item, propertyKey); + }; + } else { + callback = function(item) { + return get(item, propertyKey) === value; + }; + } + + return filter(dependentKey + '.@each.' + propertyKey, callback); + } + + __exports__.filterBy = filterBy;/** + @method computed.filterProperty + @for Ember + @param dependentKey + @param propertyKey + @param value + @deprecated Use `Ember.computed.filterBy` instead + */ + var filterProperty = filterBy; + __exports__.filterProperty = filterProperty; + /** + A computed property which returns a new array with all the unique + elements from one or more dependent arrays. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + uniqueFruits: Ember.computed.uniq('fruits') + }); + + var hamster = Hamster.create({ + fruits: [ + 'banana', + 'grape', + 'kale', + 'banana' + ] + }); + + hamster.get('uniqueFruits'); // ['banana', 'grape', 'kale'] + ``` + + @method computed.uniq + @for Ember + @param {String} propertyKey* + @return {Ember.ComputedProperty} computes a new array with all the + unique elements from the dependent array + */ + function uniq() { + var args = a_slice.call(arguments); + + args.push({ + initialize: function(array, changeMeta, instanceMeta) { + instanceMeta.itemCounts = {}; + }, + + addedItem: function(array, item, changeMeta, instanceMeta) { + var guid = guidFor(item); + + if (!instanceMeta.itemCounts[guid]) { + instanceMeta.itemCounts[guid] = 1; + array.pushObject(item); + } else { + ++instanceMeta.itemCounts[guid]; + } + return array; + }, + + removedItem: function(array, item, _, instanceMeta) { + var guid = guidFor(item); + var itemCounts = instanceMeta.itemCounts; + + if (--itemCounts[guid] === 0) { + array.removeObject(item); + } + + return array; + } + }); + + return arrayComputed.apply(null, args); + } + + __exports__.uniq = uniq;/** + Alias for [Ember.computed.uniq](/api/#method_computed_uniq). + + @method computed.union + @for Ember + @param {String} propertyKey* + @return {Ember.ComputedProperty} computes a new array with all the + unique elements from the dependent array + */ + var union = uniq; + __exports__.union = union; + /** + A computed property which returns a new array with all the duplicated + elements from two or more dependent arrays. + + Example + + ```javascript + var obj = Ember.Object.createWithMixins({ + adaFriends: ['Charles Babbage', 'John Hobhouse', 'William King', 'Mary Somerville'], + charlesFriends: ['William King', 'Mary Somerville', 'Ada Lovelace', 'George Peacock'], + friendsInCommon: Ember.computed.intersect('adaFriends', 'charlesFriends') + }); + + obj.get('friendsInCommon'); // ['William King', 'Mary Somerville'] + ``` + + @method computed.intersect + @for Ember + @param {String} propertyKey* + @return {Ember.ComputedProperty} computes a new array with all the + duplicated elements from the dependent arrays + */ + function intersect() { + var args = a_slice.call(arguments); + + args.push({ + initialize: function (array, changeMeta, instanceMeta) { + instanceMeta.itemCounts = {}; + }, + + addedItem: function(array, item, changeMeta, instanceMeta) { + var itemGuid = guidFor(item); + var dependentGuid = guidFor(changeMeta.arrayChanged); + var numberOfDependentArrays = changeMeta.property._dependentKeys.length; + var itemCounts = instanceMeta.itemCounts; + + if (!itemCounts[itemGuid]) { + itemCounts[itemGuid] = {}; + } + + if (itemCounts[itemGuid][dependentGuid] === undefined) { + itemCounts[itemGuid][dependentGuid] = 0; + } + + if (++itemCounts[itemGuid][dependentGuid] === 1 && + numberOfDependentArrays === keys(itemCounts[itemGuid]).length) { + array.addObject(item); + } + + return array; + }, + + removedItem: function(array, item, changeMeta, instanceMeta) { + var itemGuid = guidFor(item); + var dependentGuid = guidFor(changeMeta.arrayChanged); + var numberOfDependentArrays = changeMeta.property._dependentKeys.length; + var numberOfArraysItemAppearsIn; + var itemCounts = instanceMeta.itemCounts; + + if (itemCounts[itemGuid][dependentGuid] === undefined) { + itemCounts[itemGuid][dependentGuid] = 0; + } + + if (--itemCounts[itemGuid][dependentGuid] === 0) { + delete itemCounts[itemGuid][dependentGuid]; + numberOfArraysItemAppearsIn = keys(itemCounts[itemGuid]).length; + + if (numberOfArraysItemAppearsIn === 0) { + delete itemCounts[itemGuid]; + } + + array.removeObject(item); + } + + return array; + } + }); + + return arrayComputed.apply(null, args); + } + + __exports__.intersect = intersect;/** + A computed property which returns a new array with all the + properties from the first dependent array that are not in the second + dependent array. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + likes: ['banana', 'grape', 'kale'], + wants: Ember.computed.setDiff('likes', 'fruits') + }); + + var hamster = Hamster.create({ + fruits: [ + 'grape', + 'kale', + ] + }); + + hamster.get('wants'); // ['banana'] + ``` + + @method computed.setDiff + @for Ember + @param {String} setAProperty + @param {String} setBProperty + @return {Ember.ComputedProperty} computes a new array with all the + items from the first dependent array that are not in the second + dependent array + */ + function setDiff(setAProperty, setBProperty) { + if (arguments.length !== 2) { + throw new EmberError('setDiff requires exactly two dependent arrays.'); + } + + return arrayComputed(setAProperty, setBProperty, { + addedItem: function (array, item, changeMeta, instanceMeta) { + var setA = get(this, setAProperty); + var setB = get(this, setBProperty); + + if (changeMeta.arrayChanged === setA) { + if (!setB.contains(item)) { + array.addObject(item); + } + } else { + array.removeObject(item); + } + + return array; + }, + + removedItem: function (array, item, changeMeta, instanceMeta) { + var setA = get(this, setAProperty); + var setB = get(this, setBProperty); + + if (changeMeta.arrayChanged === setB) { + if (setA.contains(item)) { + array.addObject(item); + } + } else { + array.removeObject(item); + } + + return array; + } + }); + } + + __exports__.setDiff = setDiff;function binarySearch(array, item, low, high) { + var mid, midItem, res, guidMid, guidItem; + + if (arguments.length < 4) { + high = get(array, 'length'); + } + + if (arguments.length < 3) { + low = 0; + } + + if (low === high) { + return low; + } + + mid = low + Math.floor((high - low) / 2); + midItem = array.objectAt(mid); + + guidMid = guidFor(midItem); + guidItem = guidFor(item); + + if (guidMid === guidItem) { + return mid; + } + + res = this.order(midItem, item); + + if (res === 0) { + res = guidMid < guidItem ? -1 : 1; + } + + + if (res < 0) { + return this.binarySearch(array, item, mid+1, high); + } else if (res > 0) { + return this.binarySearch(array, item, low, mid); + } + + return mid; + } + + + /** + A computed property which returns a new array with all the + properties from the first dependent array sorted based on a property + or sort function. + + The callback method you provide should have the following signature: + + ```javascript + function(itemA, itemB); + ``` + + - `itemA` the first item to compare. + - `itemB` the second item to compare. + + This function should return negative number (e.g. `-1`) when `itemA` should come before + `itemB`. It should return positive number (e.g. `1`) when `itemA` should come after + `itemB`. If the `itemA` and `itemB` are equal this function should return `0`. + + Therefore, if this function is comparing some numeric values, simple `itemA - itemB` or + `itemA.get( 'foo' ) - itemB.get( 'foo' )` can be used instead of series of `if`. + + Example + + ```javascript + var ToDoList = Ember.Object.extend({ + // using standard ascending sort + todosSorting: ['name'], + sortedTodos: Ember.computed.sort('todos', 'todosSorting'), + + // using descending sort + todosSortingDesc: ['name:desc'], + sortedTodosDesc: Ember.computed.sort('todos', 'todosSortingDesc'), + + // using a custom sort function + priorityTodos: Ember.computed.sort('todos', function(a, b){ + if (a.priority > b.priority) { + return 1; + } else if (a.priority < b.priority) { + return -1; + } + + return 0; + }) + }); + + var todoList = ToDoList.create({todos: [ + { name: 'Unit Test', priority: 2 }, + { name: 'Documentation', priority: 3 }, + { name: 'Release', priority: 1 } + ]}); + + todoList.get('sortedTodos'); // [{ name:'Documentation', priority:3 }, { name:'Release', priority:1 }, { name:'Unit Test', priority:2 }] + todoList.get('sortedTodosDesc'); // [{ name:'Unit Test', priority:2 }, { name:'Release', priority:1 }, { name:'Documentation', priority:3 }] + todoList.get('priorityTodos'); // [{ name:'Release', priority:1 }, { name:'Unit Test', priority:2 }, { name:'Documentation', priority:3 }] + ``` + + @method computed.sort + @for Ember + @param {String} dependentKey + @param {String or Function} sortDefinition a dependent key to an + array of sort properties (add `:desc` to the arrays sort properties to sort descending) or a function to use when sorting + @return {Ember.ComputedProperty} computes a new sorted array based + on the sort property array or callback function + */ + function sort(itemsKey, sortDefinition) { + Ember.assert('Ember.computed.sort requires two arguments: an array key to sort and ' + + 'either a sort properties key or sort function', arguments.length === 2); + + if (typeof sortDefinition === 'function') { + return customSort(itemsKey, sortDefinition); + } else { + return propertySort(itemsKey, sortDefinition); + } + } + + __exports__.sort = sort;function customSort(itemsKey, comparator) { + return arrayComputed(itemsKey, { + initialize: function (array, changeMeta, instanceMeta) { + instanceMeta.order = comparator; + instanceMeta.binarySearch = binarySearch; + instanceMeta.waitingInsertions = []; + instanceMeta.insertWaiting = function() { + var index, item; + var waiting = instanceMeta.waitingInsertions; + instanceMeta.waitingInsertions = []; + for (var i=0; i{{post.title}} ({{post.titleLength}} characters) + {{/each}} + ``` + + ```javascript + App.PostsController = Ember.ArrayController.extend({ + itemController: 'post' + }); + + App.PostController = Ember.ObjectController.extend({ + // the `title` property will be proxied to the underlying post. + titleLength: function() { + return this.get('title').length; + }.property('title') + }); + ``` + + In some cases it is helpful to return a different `itemController` depending + on the particular item. Subclasses can do this by overriding + `lookupItemController`. + + For example: + + ```javascript + App.MyArrayController = Ember.ArrayController.extend({ + lookupItemController: function( object ) { + if (object.get('isSpecial')) { + return "special"; // use App.SpecialController + } else { + return "regular"; // use App.RegularController + } + } + }); + ``` + + The itemController instances will have a `parentController` property set to + the `ArrayController` instance. + + @class ArrayController + @namespace Ember + @extends Ember.ArrayProxy + @uses Ember.SortableMixin + @uses Ember.ControllerMixin + */ + + __exports__["default"] = ArrayProxy.extend(ControllerMixin, SortableMixin, { + + /** + The controller used to wrap items, if any. If the value is a string, it will + be used to lookup the container for the controller. As an alternative, you + can also provide a controller class as the value. + + For example: + + ```javascript + App.MyArrayController = Ember.ArrayController.extend({ + itemController: Ember.ObjectController.extend({ + //Item Controller Implementation + }) + }); + ``` + + @property itemController + @type String | Ember.Controller + @default null + */ + itemController: null, + + /** + Return the name of the controller to wrap items, or `null` if items should + be returned directly. The default implementation simply returns the + `itemController` property, but subclasses can override this method to return + different controllers for different objects. + + For example: + + ```javascript + App.MyArrayController = Ember.ArrayController.extend({ + lookupItemController: function( object ) { + if (object.get('isSpecial')) { + return "special"; // use App.SpecialController + } else { + return "regular"; // use App.RegularController + } + } + }); + ``` + + @method lookupItemController + @param {Object} object + @return {String} + */ + lookupItemController: function(object) { + return get(this, 'itemController'); + }, + + objectAtContent: function(idx) { + var length = get(this, 'length'); + var arrangedContent = get(this, 'arrangedContent'); + var object = arrangedContent && arrangedContent.objectAt(idx); + var controllerClass; + + if (idx >= 0 && idx < length) { + controllerClass = this.lookupItemController(object); + + if (controllerClass) { + return this.controllerAt(idx, object, controllerClass); + } + } + + // When `controllerClass` is falsy, we have not opted in to using item + // controllers, so return the object directly. + + // When the index is out of range, we want to return the "out of range" + // value, whatever that might be. Rather than make assumptions + // (e.g. guessing `null` or `undefined`) we defer this to `arrangedContent`. + return object; + }, + + arrangedContentDidChange: function() { + this._super(); + this._resetSubControllers(); + }, + + arrayContentDidChange: function(idx, removedCnt, addedCnt) { + var subControllers = this._subControllers; + + if (subControllers.length) { + var subControllersToRemove = subControllers.slice(idx, idx + removedCnt); + + forEach(subControllersToRemove, function(subController) { + if (subController) { + subController.destroy(); + } + }); + + replace(subControllers, idx, removedCnt, new Array(addedCnt)); + } + + // The shadow array of subcontrollers must be updated before we trigger + // observers, otherwise observers will get the wrong subcontainer when + // calling `objectAt` + this._super(idx, removedCnt, addedCnt); + }, + + init: function() { + this._super(); + this._subControllers = []; + }, + + model: computed(function () { + return Ember.A(); + }), + + /** + * Flag to mark as being "virtual". Used to keep this instance + * from participating in the parentController hierarchy. + * + * @private + * @property _isVirtual + * @type Boolean + */ + _isVirtual: false, + + controllerAt: function(idx, object, controllerClass) { + var container = get(this, 'container'); + var subControllers = this._subControllers; + var fullName, subController, subControllerFactory, parentController, options; + + if (subControllers.length > idx) { + subController = subControllers[idx]; + + if (subController) { + return subController; + } + } + + if (this._isVirtual) { + parentController = get(this, 'parentController'); + } else { + parentController = this; + } + + + fullName = 'controller:' + controllerClass; + + if (!container.has(fullName)) { + throw new EmberError('Could not resolve itemController: "' + controllerClass + '"'); + } + + subController = container.lookupFactory(fullName).create({ + target: parentController, + parentController: parentController, + model: object + }); + + + subControllers[idx] = subController; + + return subController; + }, + + _subControllers: null, + + _resetSubControllers: function() { + var controller; + var subControllers = this._subControllers; + + if (subControllers.length) { + for (var i = 0, length = subControllers.length; length > i; i++) { + controller = subControllers[i]; + + if (controller) { + controller.destroy(); + } + } + + subControllers.length = 0; + } + }, + + willDestroy: function() { + this._resetSubControllers(); + this._super(); + } + }); + }); +enifed("ember-runtime/controllers/controller", + ["ember-runtime/system/object","ember-runtime/mixins/controller","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var EmberObject = __dependency1__["default"]; + var Mixin = __dependency2__["default"]; + + /** + @module ember + @submodule ember-runtime + */ + + /** + @class Controller + @namespace Ember + @extends Ember.Object + @uses Ember.ControllerMixin + */ + __exports__["default"] = EmberObject.extend(Mixin); + }); +enifed("ember-runtime/controllers/object_controller", + ["ember-runtime/mixins/controller","ember-runtime/system/object_proxy","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var ControllerMixin = __dependency1__["default"]; + var ObjectProxy = __dependency2__["default"]; + + /** + @module ember + @submodule ember-runtime + */ + + /** + `Ember.ObjectController` is part of Ember's Controller layer. It is intended + to wrap a single object, proxying unhandled attempts to `get` and `set` to the underlying + model object, and to forward unhandled action attempts to its `target`. + + `Ember.ObjectController` derives this functionality from its superclass + `Ember.ObjectProxy` and the `Ember.ControllerMixin` mixin. + + @class ObjectController + @namespace Ember + @extends Ember.ObjectProxy + @uses Ember.ControllerMixin + **/ + __exports__["default"] = ObjectProxy.extend(ControllerMixin); + }); +enifed("ember-runtime/copy", + ["ember-metal/enumerable_utils","ember-metal/utils","ember-runtime/system/object","ember-runtime/mixins/copyable","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var indexOf = __dependency1__.indexOf; + var typeOf = __dependency2__.typeOf; + var EmberObject = __dependency3__["default"]; + var Copyable = __dependency4__["default"]; + + function _copy(obj, deep, seen, copies) { + var ret, loc, key; + + // primitive data types are immutable, just return them. + if (typeof obj !== 'object' || obj === null) { + return obj; + } + + // avoid cyclical loops + if (deep && (loc = indexOf(seen, obj)) >= 0) { + return copies[loc]; + } + + Ember.assert('Cannot clone an Ember.Object that does not implement Ember.Copyable', + !(obj instanceof EmberObject) || (Copyable && Copyable.detect(obj))); + + // IMPORTANT: this specific test will detect a native array only. Any other + // object will need to implement Copyable. + if (typeOf(obj) === 'array') { + ret = obj.slice(); + + if (deep) { + loc = ret.length; + + while (--loc >= 0) { + ret[loc] = _copy(ret[loc], deep, seen, copies); + } + } + } else if (Copyable && Copyable.detect(obj)) { + ret = obj.copy(deep, seen, copies); + } else if (obj instanceof Date) { + ret = new Date(obj.getTime()); + } else { + ret = {}; + + for (key in obj) { + // support Null prototype + if (!Object.prototype.hasOwnProperty.call(obj, key)) { + continue; + } + + // Prevents browsers that don't respect non-enumerability from + // copying internal Ember properties + if (key.substring(0, 2) === '__') { + continue; + } + + ret[key] = deep ? _copy(obj[key], deep, seen, copies) : obj[key]; + } + } + + if (deep) { + seen.push(obj); + copies.push(ret); + } + + return ret; + } + + /** + Creates a clone of the passed object. This function can take just about + any type of object and create a clone of it, including primitive values + (which are not actually cloned because they are immutable). + + If the passed object implements the `clone()` method, then this function + will simply call that method and return the result. + + @method copy + @for Ember + @param {Object} obj The object to clone + @param {Boolean} deep If true, a deep copy of the object is made + @return {Object} The cloned object + */ + __exports__["default"] = function copy(obj, deep) { + // fast paths + if ('object' !== typeof obj || obj === null) { + return obj; // can't copy primitives + } + + if (Copyable && Copyable.detect(obj)) { + return obj.copy(deep); + } + + return _copy(obj, deep, deep ? [] : null, deep ? [] : null); + } + }); +enifed("ember-runtime/core", + ["exports"], + function(__exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + /** + Compares two objects, returning true if they are logically equal. This is + a deeper comparison than a simple triple equal. For sets it will compare the + internal objects. For any other object that implements `isEqual()` it will + respect that method. + + ```javascript + Ember.isEqual('hello', 'hello'); // true + Ember.isEqual(1, 2); // false + Ember.isEqual([4, 2], [4, 2]); // false + ``` + + @method isEqual + @for Ember + @param {Object} a first object to compare + @param {Object} b second object to compare + @return {Boolean} + */ + var isEqual = function isEqual(a, b) { + if (a && typeof a.isEqual === 'function') { + return a.isEqual(b); + } + + if (a instanceof Date && b instanceof Date) { + return a.getTime() === b.getTime(); + } + + return a === b; + }; + __exports__.isEqual = isEqual; + }); +enifed("ember-runtime/ext/function", + ["ember-metal/core","ember-metal/expand_properties","ember-metal/computed","ember-metal/mixin"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + // Ember.EXTEND_PROTOTYPES, Ember.assert + var expandProperties = __dependency2__["default"]; + var computed = __dependency3__.computed; + var observer = __dependency4__.observer; + + var a_slice = Array.prototype.slice; + var FunctionPrototype = Function.prototype; + + if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Function) { + + /** + The `property` extension of Javascript's Function prototype is available + when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is + `true`, which is the default. + + Computed properties allow you to treat a function like a property: + + ```javascript + MyApp.President = Ember.Object.extend({ + firstName: '', + lastName: '', + + fullName: function() { + return this.get('firstName') + ' ' + this.get('lastName'); + }.property() // Call this flag to mark the function as a property + }); + + var president = MyApp.President.create({ + firstName: 'Barack', + lastName: 'Obama' + }); + + president.get('fullName'); // 'Barack Obama' + ``` + + Treating a function like a property is useful because they can work with + bindings, just like any other property. + + Many computed properties have dependencies on other properties. For + example, in the above example, the `fullName` property depends on + `firstName` and `lastName` to determine its value. You can tell Ember + about these dependencies like this: + + ```javascript + MyApp.President = Ember.Object.extend({ + firstName: '', + lastName: '', + + fullName: function() { + return this.get('firstName') + ' ' + this.get('lastName'); + + // Tell Ember.js that this computed property depends on firstName + // and lastName + }.property('firstName', 'lastName') + }); + ``` + + Make sure you list these dependencies so Ember knows when to update + bindings that connect to a computed property. Changing a dependency + will not immediately trigger an update of the computed property, but + will instead clear the cache so that it is updated when the next `get` + is called on the property. + + See [Ember.ComputedProperty](/api/classes/Ember.ComputedProperty.html), [Ember.computed](/api/#method_computed). + + @method property + @for Function + */ + FunctionPrototype.property = function () { + var ret = computed(this); + // ComputedProperty.prototype.property expands properties; no need for us to + // do so here. + return ret.property.apply(ret, arguments); + }; + + /** + The `observes` extension of Javascript's Function prototype is available + when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is + true, which is the default. + + You can observe property changes simply by adding the `observes` + call to the end of your method declarations in classes that you write. + For example: + + ```javascript + Ember.Object.extend({ + valueObserver: function() { + // Executes whenever the "value" property changes + }.observes('value') + }); + ``` + + In the future this method may become asynchronous. If you want to ensure + synchronous behavior, use `observesImmediately`. + + See `Ember.observer`. + + @method observes + @for Function + */ + FunctionPrototype.observes = function() { + var length = arguments.length; + var args = new Array(length); + for (var x = 0; x < length; x++) { + args[x] = arguments[x]; + } + return observer.apply(this, args.concat(this)); + }; + + /** + The `observesImmediately` extension of Javascript's Function prototype is + available when `Ember.EXTEND_PROTOTYPES` or + `Ember.EXTEND_PROTOTYPES.Function` is true, which is the default. + + You can observe property changes simply by adding the `observesImmediately` + call to the end of your method declarations in classes that you write. + For example: + + ```javascript + Ember.Object.extend({ + valueObserver: function() { + // Executes immediately after the "value" property changes + }.observesImmediately('value') + }); + ``` + + In the future, `observes` may become asynchronous. In this event, + `observesImmediately` will maintain the synchronous behavior. + + See `Ember.immediateObserver`. + + @method observesImmediately + @for Function + */ + FunctionPrototype.observesImmediately = function () { + for (var i = 0, l = arguments.length; i < l; i++) { + var arg = arguments[i]; + Ember.assert('Immediate observers must observe internal properties only, ' + + 'not properties on other objects.', arg.indexOf('.') === -1); + } + + // observes handles property expansion + return this.observes.apply(this, arguments); + }; + + /** + The `observesBefore` extension of Javascript's Function prototype is + available when `Ember.EXTEND_PROTOTYPES` or + `Ember.EXTEND_PROTOTYPES.Function` is true, which is the default. + + You can get notified when a property change is about to happen by + by adding the `observesBefore` call to the end of your method + declarations in classes that you write. For example: + + ```javascript + Ember.Object.extend({ + valueObserver: function() { + // Executes whenever the "value" property is about to change + }.observesBefore('value') + }); + ``` + + See `Ember.beforeObserver`. + + @method observesBefore + @for Function + */ + FunctionPrototype.observesBefore = function () { + var watched = []; + var addWatchedProperty = function (obs) { + watched.push(obs); + }; + + for (var i = 0, l = arguments.length; i < l; ++i) { + expandProperties(arguments[i], addWatchedProperty); + } + + this.__ember_observesBefore__ = watched; + + return this; + }; + + /** + The `on` extension of Javascript's Function prototype is available + when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is + true, which is the default. + + You can listen for events simply by adding the `on` call to the end of + your method declarations in classes or mixins that you write. For example: + + ```javascript + Ember.Mixin.create({ + doSomethingWithElement: function() { + // Executes whenever the "didInsertElement" event fires + }.on('didInsertElement') + }); + ``` + + See `Ember.on`. + + @method on + @for Function + */ + FunctionPrototype.on = function () { + var events = a_slice.call(arguments); + this.__ember_listens__ = events; + + return this; + }; + } + }); +enifed("ember-runtime/ext/rsvp", + ["ember-metal/core","ember-metal/logger","ember-metal/run_loop","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + /* globals RSVP:true */ + + var Ember = __dependency1__["default"]; + var Logger = __dependency2__["default"]; + var run = __dependency3__["default"]; + + var RSVP = requireModule('rsvp'); + var testModuleName = 'ember-testing/test'; + var Test; + + var asyncStart = function() { + if (Ember.Test && Ember.Test.adapter) { + Ember.Test.adapter.asyncStart(); + } + }; + + var asyncEnd = function() { + if (Ember.Test && Ember.Test.adapter) { + Ember.Test.adapter.asyncEnd(); + } + }; + + RSVP.configure('async', function(callback, promise) { + var async = !run.currentRunLoop; + + if (Ember.testing && async) { asyncStart(); } + + run.backburner.schedule('actions', function(){ + if (Ember.testing && async) { asyncEnd(); } + callback(promise); + }); + }); + + RSVP.Promise.prototype.fail = function(callback, label){ + Ember.deprecate('RSVP.Promise.fail has been renamed as RSVP.Promise.catch'); + return this['catch'](callback, label); + }; + + RSVP.onerrorDefault = function (error) { + if (error instanceof Error) { + if (Ember.testing) { + // ES6TODO: remove when possible + if (!Test && Ember.__loader.registry[testModuleName]) { + Test = requireModule(testModuleName)['default']; + } + + if (Test && Test.adapter) { + Test.adapter.exception(error); + } else { + throw error; + } + } else if (Ember.onerror) { + Ember.onerror(error); + } else { + Logger.error(error.stack); + Ember.assert(error, false); + } + } + }; + + RSVP.on('error', RSVP.onerrorDefault); + + __exports__["default"] = RSVP; + }); +enifed("ember-runtime/ext/string", + ["ember-metal/core","ember-runtime/system/string"], + function(__dependency1__, __dependency2__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + // Ember.EXTEND_PROTOTYPES, Ember.assert, Ember.FEATURES + var fmt = __dependency2__.fmt; + var w = __dependency2__.w; + var loc = __dependency2__.loc; + var camelize = __dependency2__.camelize; + var decamelize = __dependency2__.decamelize; + var dasherize = __dependency2__.dasherize; + var underscore = __dependency2__.underscore; + var capitalize = __dependency2__.capitalize; + var classify = __dependency2__.classify; + + var StringPrototype = String.prototype; + + if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) { + + /** + See [Ember.String.fmt](/api/classes/Ember.String.html#method_fmt). + + @method fmt + @for String + */ + StringPrototype.fmt = function () { + return fmt(this, arguments); + }; + + /** + See [Ember.String.w](/api/classes/Ember.String.html#method_w). + + @method w + @for String + */ + StringPrototype.w = function () { + return w(this); + }; + + /** + See [Ember.String.loc](/api/classes/Ember.String.html#method_loc). + + @method loc + @for String + */ + StringPrototype.loc = function () { + return loc(this, arguments); + }; + + /** + See [Ember.String.camelize](/api/classes/Ember.String.html#method_camelize). + + @method camelize + @for String + */ + StringPrototype.camelize = function () { + return camelize(this); + }; + + /** + See [Ember.String.decamelize](/api/classes/Ember.String.html#method_decamelize). + + @method decamelize + @for String + */ + StringPrototype.decamelize = function () { + return decamelize(this); + }; + + /** + See [Ember.String.dasherize](/api/classes/Ember.String.html#method_dasherize). + + @method dasherize + @for String + */ + StringPrototype.dasherize = function () { + return dasherize(this); + }; + + /** + See [Ember.String.underscore](/api/classes/Ember.String.html#method_underscore). + + @method underscore + @for String + */ + StringPrototype.underscore = function () { + return underscore(this); + }; + + /** + See [Ember.String.classify](/api/classes/Ember.String.html#method_classify). + + @method classify + @for String + */ + StringPrototype.classify = function () { + return classify(this); + }; + + /** + See [Ember.String.capitalize](/api/classes/Ember.String.html#method_capitalize). + + @method capitalize + @for String + */ + StringPrototype.capitalize = function () { + return capitalize(this); + }; + } + }); +enifed("ember-runtime/mixins/-proxy", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/observer","ember-metal/property_events","ember-metal/computed","ember-metal/properties","ember-metal/mixin","ember-runtime/system/string","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + // Ember.assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var meta = __dependency4__.meta; + var addObserver = __dependency5__.addObserver; + var removeObserver = __dependency5__.removeObserver; + var addBeforeObserver = __dependency5__.addBeforeObserver; + var removeBeforeObserver = __dependency5__.removeBeforeObserver; + var propertyWillChange = __dependency6__.propertyWillChange; + var propertyDidChange = __dependency6__.propertyDidChange; + var computed = __dependency7__.computed; + var defineProperty = __dependency8__.defineProperty; + var Mixin = __dependency9__.Mixin; + var observer = __dependency9__.observer; + var fmt = __dependency10__.fmt; + var EmberObject = __dependency11__["default"]; + + function contentPropertyWillChange(content, contentKey) { + var key = contentKey.slice(8); // remove "content." + if (key in this) { return; } // if shadowed in proxy + propertyWillChange(this, key); + } + + function contentPropertyDidChange(content, contentKey) { + var key = contentKey.slice(8); // remove "content." + if (key in this) { return; } // if shadowed in proxy + propertyDidChange(this, key); + } + + /** + `Ember.ProxyMixin` forwards all properties not defined by the proxy itself + to a proxied `content` object. See Ember.ObjectProxy for more details. + + @class ProxyMixin + @namespace Ember + */ + __exports__["default"] = Mixin.create({ + /** + The object whose properties will be forwarded. + + @property content + @type Ember.Object + @default null + */ + content: null, + _contentDidChange: observer('content', function() { + Ember.assert("Can't set Proxy's content to itself", get(this, 'content') !== this); + }), + + isTruthy: computed.bool('content'), + + _debugContainerKey: null, + + willWatchProperty: function (key) { + var contentKey = 'content.' + key; + addBeforeObserver(this, contentKey, null, contentPropertyWillChange); + addObserver(this, contentKey, null, contentPropertyDidChange); + }, + + didUnwatchProperty: function (key) { + var contentKey = 'content.' + key; + removeBeforeObserver(this, contentKey, null, contentPropertyWillChange); + removeObserver(this, contentKey, null, contentPropertyDidChange); + }, + + unknownProperty: function (key) { + var content = get(this, 'content'); + if (content) { + return get(content, key); + } + }, + + setUnknownProperty: function (key, value) { + var m = meta(this); + if (m.proto === this) { + // if marked as prototype then just defineProperty + // rather than delegate + defineProperty(this, key, null, value); + return value; + } + + var content = get(this, 'content'); + Ember.assert(fmt("Cannot delegate set('%@', %@) to the 'content' property of object proxy %@: its 'content' is undefined.", [key, value, this]), content); + return set(content, key, value); + } + + }); + }); +enifed("ember-runtime/mixins/action_handler", + ["ember-metal/merge","ember-metal/mixin","ember-metal/property_get","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + var merge = __dependency1__["default"]; + var Mixin = __dependency2__.Mixin; + var get = __dependency3__.get; + var typeOf = __dependency4__.typeOf; + + /** + The `Ember.ActionHandler` mixin implements support for moving an `actions` + property to an `_actions` property at extend time, and adding `_actions` + to the object's mergedProperties list. + + `Ember.ActionHandler` is available on some familiar classes including + `Ember.Route`, `Ember.View`, `Ember.Component`, and controllers such as + `Ember.Controller` and `Ember.ObjectController`. + (Internally the mixin is used by `Ember.CoreView`, `Ember.ControllerMixin`, + and `Ember.Route` and available to the above classes through + inheritance.) + + @class ActionHandler + @namespace Ember + */ + var ActionHandler = Mixin.create({ + mergedProperties: ['_actions'], + + /** + The collection of functions, keyed by name, available on this + `ActionHandler` as action targets. + + These functions will be invoked when a matching `{{action}}` is triggered + from within a template and the application's current route is this route. + + Actions can also be invoked from other parts of your application + via `ActionHandler#send`. + + The `actions` hash will inherit action handlers from + the `actions` hash defined on extended parent classes + or mixins rather than just replace the entire hash, e.g.: + + ```js + App.CanDisplayBanner = Ember.Mixin.create({ + actions: { + displayBanner: function(msg) { + // ... + } + } + }); + + App.WelcomeRoute = Ember.Route.extend(App.CanDisplayBanner, { + actions: { + playMusic: function() { + // ... + } + } + }); + + // `WelcomeRoute`, when active, will be able to respond + // to both actions, since the actions hash is merged rather + // then replaced when extending mixins / parent classes. + this.send('displayBanner'); + this.send('playMusic'); + ``` + + Within a Controller, Route, View or Component's action handler, + the value of the `this` context is the Controller, Route, View or + Component object: + + ```js + App.SongRoute = Ember.Route.extend({ + actions: { + myAction: function() { + this.controllerFor("song"); + this.transitionTo("other.route"); + ... + } + } + }); + ``` + + It is also possible to call `this._super()` from within an + action handler if it overrides a handler defined on a parent + class or mixin: + + Take for example the following routes: + + ```js + App.DebugRoute = Ember.Mixin.create({ + actions: { + debugRouteInformation: function() { + console.debug("trololo"); + } + } + }); + + App.AnnoyingDebugRoute = Ember.Route.extend(App.DebugRoute, { + actions: { + debugRouteInformation: function() { + // also call the debugRouteInformation of mixed in App.DebugRoute + this._super(); + + // show additional annoyance + window.alert(...); + } + } + }); + ``` + + ## Bubbling + + By default, an action will stop bubbling once a handler defined + on the `actions` hash handles it. To continue bubbling the action, + you must return `true` from the handler: + + ```js + App.Router.map(function() { + this.resource("album", function() { + this.route("song"); + }); + }); + + App.AlbumRoute = Ember.Route.extend({ + actions: { + startPlaying: function() { + } + } + }); + + App.AlbumSongRoute = Ember.Route.extend({ + actions: { + startPlaying: function() { + // ... + + if (actionShouldAlsoBeTriggeredOnParentRoute) { + return true; + } + } + } + }); + ``` + + @property actions + @type Hash + @default null + */ + + /** + Moves `actions` to `_actions` at extend time. Note that this currently + modifies the mixin themselves, which is technically dubious but + is practically of little consequence. This may change in the future. + + @private + @method willMergeMixin + */ + willMergeMixin: function(props) { + var hashName; + + if (!props._actions) { + Ember.assert("'actions' should not be a function", typeof(props.actions) !== 'function'); + + if (typeOf(props.actions) === 'object') { + hashName = 'actions'; + } else if (typeOf(props.events) === 'object') { + Ember.deprecate('Action handlers contained in an `events` object are deprecated in favor of putting them in an `actions` object', false); + hashName = 'events'; + } + + if (hashName) { + props._actions = merge(props._actions || {}, props[hashName]); + } + + delete props[hashName]; + } + }, + + /** + Triggers a named action on the `ActionHandler`. Any parameters + supplied after the `actionName` string will be passed as arguments + to the action target function. + + If the `ActionHandler` has its `target` property set, actions may + bubble to the `target`. Bubbling happens when an `actionName` can + not be found in the `ActionHandler`'s `actions` hash or if the + action target function returns `true`. + + Example + + ```js + App.WelcomeRoute = Ember.Route.extend({ + actions: { + playTheme: function() { + this.send('playMusic', 'theme.mp3'); + }, + playMusic: function(track) { + // ... + } + } + }); + ``` + + @method send + @param {String} actionName The action to trigger + @param {*} context a context to send with the action + */ + send: function(actionName) { + var args = [].slice.call(arguments, 1); + var target; + + if (this._actions && this._actions[actionName]) { + if (this._actions[actionName].apply(this, args) === true) { + // handler returned true, so this action will bubble + } else { + return; + } + } + + if (target = get(this, 'target')) { + Ember.assert("The `target` for " + this + " (" + target + ") does not have a `send` method", typeof target.send === 'function'); + target.send.apply(target, arguments); + } + } + }); + + __exports__["default"] = ActionHandler; + }); +enifed("ember-runtime/mixins/array", + ["ember-metal/core","ember-metal/property_get","ember-metal/computed","ember-metal/is_none","ember-runtime/mixins/enumerable","ember-metal/enumerable_utils","ember-metal/mixin","ember-metal/property_events","ember-metal/events","ember-metal/watching","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + // .......................................................... + // HELPERS + // + var Ember = __dependency1__["default"]; + // ES6TODO: Ember.A + var get = __dependency2__.get; + var computed = __dependency3__.computed; + var cacheFor = __dependency3__.cacheFor; + var isNone = __dependency4__.isNone; + var none = __dependency4__.none; + var Enumerable = __dependency5__["default"]; + var map = __dependency6__.map; + var Mixin = __dependency7__.Mixin; + var required = __dependency7__.required; + var propertyWillChange = __dependency8__.propertyWillChange; + var propertyDidChange = __dependency8__.propertyDidChange; + var addListener = __dependency9__.addListener; + var removeListener = __dependency9__.removeListener; + var sendEvent = __dependency9__.sendEvent; + var hasListeners = __dependency9__.hasListeners; + var isWatching = __dependency10__.isWatching; + + function arrayObserversHelper(obj, target, opts, operation, notify) { + var willChange = (opts && opts.willChange) || 'arrayWillChange'; + var didChange = (opts && opts.didChange) || 'arrayDidChange'; + var hasObservers = get(obj, 'hasArrayObservers'); + + if (hasObservers === notify) { + propertyWillChange(obj, 'hasArrayObservers'); + } + + operation(obj, '@array:before', target, willChange); + operation(obj, '@array:change', target, didChange); + + if (hasObservers === notify) { + propertyDidChange(obj, 'hasArrayObservers'); + } + + return obj; + } + + // .......................................................... + // ARRAY + // + /** + This mixin implements Observer-friendly Array-like behavior. It is not a + concrete implementation, but it can be used up by other classes that want + to appear like arrays. + + For example, ArrayProxy and ArrayController are both concrete classes that can + be instantiated to implement array-like behavior. Both of these classes use + the Array Mixin by way of the MutableArray mixin, which allows observable + changes to be made to the underlying array. + + Unlike `Ember.Enumerable,` this mixin defines methods specifically for + collections that provide index-ordered access to their contents. When you + are designing code that needs to accept any kind of Array-like object, you + should use these methods instead of Array primitives because these will + properly notify observers of changes to the array. + + Although these methods are efficient, they do add a layer of indirection to + your application so it is a good idea to use them only when you need the + flexibility of using both true JavaScript arrays and "virtual" arrays such + as controllers and collections. + + You can use the methods defined in this module to access and modify array + contents in a KVO-friendly way. You can also be notified whenever the + membership of an array changes by using `.observes('myArray.[]')`. + + To support `Ember.Array` in your own class, you must override two + primitives to use it: `replace()` and `objectAt()`. + + Note that the Ember.Array mixin also incorporates the `Ember.Enumerable` + mixin. All `Ember.Array`-like objects are also enumerable. + + @class Array + @namespace Ember + @uses Ember.Enumerable + @since Ember 0.9.0 + */ + __exports__["default"] = Mixin.create(Enumerable, { + + /** + Your array must support the `length` property. Your replace methods should + set this property whenever it changes. + + @property {Number} length + */ + length: required(), + + /** + Returns the object at the given `index`. If the given `index` is negative + or is greater or equal than the array length, returns `undefined`. + + This is one of the primitives you must implement to support `Ember.Array`. + If your object supports retrieving the value of an array item using `get()` + (i.e. `myArray.get(0)`), then you do not need to implement this method + yourself. + + ```javascript + var arr = ['a', 'b', 'c', 'd']; + + arr.objectAt(0); // 'a' + arr.objectAt(3); // 'd' + arr.objectAt(-1); // undefined + arr.objectAt(4); // undefined + arr.objectAt(5); // undefined + ``` + + @method objectAt + @param {Number} idx The index of the item to return. + @return {*} item at index or undefined + */ + objectAt: function(idx) { + if (idx < 0 || idx >= get(this, 'length')) { + return undefined; + } + + return get(this, idx); + }, + + /** + This returns the objects at the specified indexes, using `objectAt`. + + ```javascript + var arr = ['a', 'b', 'c', 'd']; + + arr.objectsAt([0, 1, 2]); // ['a', 'b', 'c'] + arr.objectsAt([2, 3, 4]); // ['c', 'd', undefined] + ``` + + @method objectsAt + @param {Array} indexes An array of indexes of items to return. + @return {Array} + */ + objectsAt: function(indexes) { + var self = this; + + return map(indexes, function(idx) { + return self.objectAt(idx); + }); + }, + + // overrides Ember.Enumerable version + nextObject: function(idx) { + return this.objectAt(idx); + }, + + /** + This is the handler for the special array content property. If you get + this property, it will return this. If you set this property to a new + array, it will replace the current content. + + This property overrides the default property defined in `Ember.Enumerable`. + + @property [] + @return this + */ + '[]': computed(function(key, value) { + if (value !== undefined) { + this.replace(0, get(this, 'length'), value); + } + + return this; + }), + + firstObject: computed(function() { + return this.objectAt(0); + }), + + lastObject: computed(function() { + return this.objectAt(get(this, 'length') - 1); + }), + + // optimized version from Enumerable + contains: function(obj) { + return this.indexOf(obj) >= 0; + }, + + // Add any extra methods to Ember.Array that are native to the built-in Array. + /** + Returns a new array that is a slice of the receiver. This implementation + uses the observable array methods to retrieve the objects for the new + slice. + + ```javascript + var arr = ['red', 'green', 'blue']; + + arr.slice(0); // ['red', 'green', 'blue'] + arr.slice(0, 2); // ['red', 'green'] + arr.slice(1, 100); // ['green', 'blue'] + ``` + + @method slice + @param {Integer} beginIndex (Optional) index to begin slicing from. + @param {Integer} endIndex (Optional) index to end the slice at (but not included). + @return {Array} New array with specified slice + */ + slice: function(beginIndex, endIndex) { + var ret = Ember.A(); + var length = get(this, 'length'); + + if (isNone(beginIndex)) { + beginIndex = 0; + } + + if (isNone(endIndex) || (endIndex > length)) { + endIndex = length; + } + + if (beginIndex < 0) { + beginIndex = length + beginIndex; + } + + if (endIndex < 0) { + endIndex = length + endIndex; + } + + while (beginIndex < endIndex) { + ret[ret.length] = this.objectAt(beginIndex++); + } + + return ret; + }, + + /** + Returns the index of the given object's first occurrence. + If no `startAt` argument is given, the starting location to + search is 0. If it's negative, will count backward from + the end of the array. Returns -1 if no match is found. + + ```javascript + var arr = ['a', 'b', 'c', 'd', 'a']; + + arr.indexOf('a'); // 0 + arr.indexOf('z'); // -1 + arr.indexOf('a', 2); // 4 + arr.indexOf('a', -1); // 4 + arr.indexOf('b', 3); // -1 + arr.indexOf('a', 100); // -1 + ``` + + @method indexOf + @param {Object} object the item to search for + @param {Number} startAt optional starting location to search, default 0 + @return {Number} index or -1 if not found + */ + indexOf: function(object, startAt) { + var len = get(this, 'length'); + var idx; + + if (startAt === undefined) { + startAt = 0; + } + + if (startAt < 0) { + startAt += len; + } + + for (idx = startAt; idx < len; idx++) { + if (this.objectAt(idx) === object) { + return idx; + } + } + + return -1; + }, + + /** + Returns the index of the given object's last occurrence. + If no `startAt` argument is given, the search starts from + the last position. If it's negative, will count backward + from the end of the array. Returns -1 if no match is found. + + ```javascript + var arr = ['a', 'b', 'c', 'd', 'a']; + + arr.lastIndexOf('a'); // 4 + arr.lastIndexOf('z'); // -1 + arr.lastIndexOf('a', 2); // 0 + arr.lastIndexOf('a', -1); // 4 + arr.lastIndexOf('b', 3); // 1 + arr.lastIndexOf('a', 100); // 4 + ``` + + @method lastIndexOf + @param {Object} object the item to search for + @param {Number} startAt optional starting location to search, default 0 + @return {Number} index or -1 if not found + */ + lastIndexOf: function(object, startAt) { + var len = get(this, 'length'); + var idx; + + if (startAt === undefined || startAt >= len) { + startAt = len-1; + } + + if (startAt < 0) { + startAt += len; + } + + for (idx = startAt; idx >= 0; idx--) { + if (this.objectAt(idx) === object) { + return idx; + } + } + + return -1; + }, + + // .......................................................... + // ARRAY OBSERVERS + // + + /** + Adds an array observer to the receiving array. The array observer object + normally must implement two methods: + + * `arrayWillChange(observedObj, start, removeCount, addCount)` - This method will be + called just before the array is modified. + * `arrayDidChange(observedObj, start, removeCount, addCount)` - This method will be + called just after the array is modified. + + Both callbacks will be passed the observed object, starting index of the + change as well a a count of the items to be removed and added. You can use + these callbacks to optionally inspect the array during the change, clear + caches, or do any other bookkeeping necessary. + + In addition to passing a target, you can also include an options hash + which you can use to override the method names that will be invoked on the + target. + + @method addArrayObserver + @param {Object} target The observer object. + @param {Hash} opts Optional hash of configuration options including + `willChange` and `didChange` option. + @return {Ember.Array} receiver + */ + + addArrayObserver: function(target, opts) { + return arrayObserversHelper(this, target, opts, addListener, false); + }, + + /** + Removes an array observer from the object if the observer is current + registered. Calling this method multiple times with the same object will + have no effect. + + @method removeArrayObserver + @param {Object} target The object observing the array. + @param {Hash} opts Optional hash of configuration options including + `willChange` and `didChange` option. + @return {Ember.Array} receiver + */ + removeArrayObserver: function(target, opts) { + return arrayObserversHelper(this, target, opts, removeListener, true); + }, + + /** + Becomes true whenever the array currently has observers watching changes + on the array. + + @property {Boolean} hasArrayObservers + */ + hasArrayObservers: computed(function() { + return hasListeners(this, '@array:change') || hasListeners(this, '@array:before'); + }), + + /** + If you are implementing an object that supports `Ember.Array`, call this + method just before the array content changes to notify any observers and + invalidate any related properties. Pass the starting index of the change + as well as a delta of the amounts to change. + + @method arrayContentWillChange + @param {Number} startIdx The starting index in the array that will change. + @param {Number} removeAmt The number of items that will be removed. If you + pass `null` assumes 0 + @param {Number} addAmt The number of items that will be added. If you + pass `null` assumes 0. + @return {Ember.Array} receiver + */ + arrayContentWillChange: function(startIdx, removeAmt, addAmt) { + var removing, lim; + + // if no args are passed assume everything changes + if (startIdx === undefined) { + startIdx = 0; + removeAmt = addAmt = -1; + } else { + if (removeAmt === undefined) { + removeAmt = -1; + } + + if (addAmt === undefined) { + addAmt = -1; + } + } + + // Make sure the @each proxy is set up if anyone is observing @each + if (isWatching(this, '@each')) { + get(this, '@each'); + } + + sendEvent(this, '@array:before', [this, startIdx, removeAmt, addAmt]); + + if (startIdx >= 0 && removeAmt >= 0 && get(this, 'hasEnumerableObservers')) { + removing = []; + lim = startIdx + removeAmt; + + for (var idx = startIdx; idx < lim; idx++) { + removing.push(this.objectAt(idx)); + } + } else { + removing = removeAmt; + } + + this.enumerableContentWillChange(removing, addAmt); + + return this; + }, + + /** + If you are implementing an object that supports `Ember.Array`, call this + method just after the array content changes to notify any observers and + invalidate any related properties. Pass the starting index of the change + as well as a delta of the amounts to change. + + @method arrayContentDidChange + @param {Number} startIdx The starting index in the array that did change. + @param {Number} removeAmt The number of items that were removed. If you + pass `null` assumes 0 + @param {Number} addAmt The number of items that were added. If you + pass `null` assumes 0. + @return {Ember.Array} receiver + */ + arrayContentDidChange: function(startIdx, removeAmt, addAmt) { + var adding, lim; + + // if no args are passed assume everything changes + if (startIdx === undefined) { + startIdx = 0; + removeAmt = addAmt = -1; + } else { + if (removeAmt === undefined) { + removeAmt = -1; + } + + if (addAmt === undefined) { + addAmt = -1; + } + } + + if (startIdx >= 0 && addAmt >= 0 && get(this, 'hasEnumerableObservers')) { + adding = []; + lim = startIdx + addAmt; + + for (var idx = startIdx; idx < lim; idx++) { + adding.push(this.objectAt(idx)); + } + } else { + adding = addAmt; + } + + this.enumerableContentDidChange(removeAmt, adding); + sendEvent(this, '@array:change', [this, startIdx, removeAmt, addAmt]); + + var length = get(this, 'length'); + var cachedFirst = cacheFor(this, 'firstObject'); + var cachedLast = cacheFor(this, 'lastObject'); + + if (this.objectAt(0) !== cachedFirst) { + propertyWillChange(this, 'firstObject'); + propertyDidChange(this, 'firstObject'); + } + + if (this.objectAt(length-1) !== cachedLast) { + propertyWillChange(this, 'lastObject'); + propertyDidChange(this, 'lastObject'); + } + + return this; + }, + + // .......................................................... + // ENUMERATED PROPERTIES + // + + /** + Returns a special object that can be used to observe individual properties + on the array. Just get an equivalent property on this object and it will + return an enumerable that maps automatically to the named key on the + member objects. + + If you merely want to watch for any items being added or removed to the array, + use the `[]` property instead of `@each`. + + @property @each + */ + '@each': computed(function() { + if (!this.__each) { + // ES6TODO: GRRRRR + var EachProxy = requireModule('ember-runtime/system/each_proxy')['EachProxy']; + + this.__each = new EachProxy(this); + } + + return this.__each; + }) + }); + }); +enifed("ember-runtime/mixins/comparable", + ["ember-metal/mixin","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Mixin = __dependency1__.Mixin; + var required = __dependency1__.required; + + /** + @module ember + @submodule ember-runtime + */ + + /** + Implements some standard methods for comparing objects. Add this mixin to + any class you create that can compare its instances. + + You should implement the `compare()` method. + + @class Comparable + @namespace Ember + @since Ember 0.9 + */ + __exports__["default"] = Mixin.create({ + + /** + Override to return the result of the comparison of the two parameters. The + compare method should return: + + - `-1` if `a < b` + - `0` if `a == b` + - `1` if `a > b` + + Default implementation raises an exception. + + @method compare + @param a {Object} the first object to compare + @param b {Object} the second object to compare + @return {Integer} the result of the comparison + */ + compare: required(Function) + }); + }); +enifed("ember-runtime/mixins/controller", + ["ember-metal/core","ember-metal/property_get","ember-runtime/system/object","ember-metal/mixin","ember-metal/computed","ember-runtime/mixins/action_handler","ember-runtime/mixins/controller_content_model_alias_deprecation","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert, Ember.deprecate + var get = __dependency2__.get; + var EmberObject = __dependency3__["default"]; + var Mixin = __dependency4__.Mixin; + var computed = __dependency5__.computed; + var ActionHandler = __dependency6__["default"]; + var ControllerContentModelAliasDeprecation = __dependency7__["default"]; + + /** + `Ember.ControllerMixin` provides a standard interface for all classes that + compose Ember's controller layer: `Ember.Controller`, + `Ember.ArrayController`, and `Ember.ObjectController`. + + @class ControllerMixin + @namespace Ember + @uses Ember.ActionHandler + */ + __exports__["default"] = Mixin.create(ActionHandler, ControllerContentModelAliasDeprecation, { + /* ducktype as a controller */ + isController: true, + + /** + The object to which actions from the view should be sent. + + For example, when a Handlebars template uses the `{{action}}` helper, + it will attempt to send the action to the view's controller's `target`. + + By default, the value of the target property is set to the router, and + is injected when a controller is instantiated. This injection is defined + in Ember.Application#buildContainer, and is applied as part of the + applications initialization process. It can also be set after a controller + has been instantiated, for instance when using the render helper in a + template, or when a controller is used as an `itemController`. In most + cases the `target` property will automatically be set to the logical + consumer of actions for the controller. + + @property target + @default null + */ + target: null, + + container: null, + + parentController: null, + + store: null, + + /** + The controller's current model. When retrieving or modifying a controller's + model, this property should be used instead of the `content` property. + + @property model + @public + */ + model: null, + + /** + @private + */ + content: computed.alias('model') + + }); + }); +enifed("ember-runtime/mixins/controller_content_model_alias_deprecation", + ["ember-metal/core","ember-metal/property_get","ember-metal/mixin","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.deprecate + var get = __dependency2__.get; + var Mixin = __dependency3__.Mixin; + + /** + The ControllerContentModelAliasDeprecation mixin is used to provide a useful + deprecation warning when specifying `content` directly on a `Ember.Controller` + (without also specifying `model`). + + Ember versions prior to 1.7 used `model` as an alias of `content`, but due to + much confusion this alias was reversed (so `content` is now an alias of `model). + + This change reduces many caveats with model/content, and also sets a + simple ground rule: Never set a controllers content, rather always set + it's model and ember will do the right thing. + + + `Ember.ControllerContentModelAliasDeprecation` is used internally by Ember in + `Ember.Controller`. + + @class ControllerContentModelAliasDeprecation + @namespace Ember + @private + @since 1.7.0 + */ + __exports__["default"] = Mixin.create({ + /** + @private + + Moves `content` to `model` at extend time if a `model` is not also specified. + + Note that this currently modifies the mixin themselves, which is technically + dubious but is practically of little consequence. This may change in the + future. + + @method willMergeMixin + @since 1.4.0 + */ + willMergeMixin: function(props) { + // Calling super is only OK here since we KNOW that + // there is another Mixin loaded first. + this._super.apply(this, arguments); + + var modelSpecified = !!props.model; + + if (props.content && !modelSpecified) { + props.model = props.content; + delete props['content']; + + Ember.deprecate('Do not specify `content` on a Controller, use `model` instead.', false); + } + } + }); + }); +enifed("ember-runtime/mixins/copyable", + ["ember-metal/property_get","ember-metal/property_set","ember-metal/mixin","ember-runtime/mixins/freezable","ember-runtime/system/string","ember-metal/error","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + + var get = __dependency1__.get; + var set = __dependency2__.set; + var required = __dependency3__.required; + var Freezable = __dependency4__.Freezable; + var Mixin = __dependency3__.Mixin; + var fmt = __dependency5__.fmt; + var EmberError = __dependency6__["default"]; + + + /** + Implements some standard methods for copying an object. Add this mixin to + any object you create that can create a copy of itself. This mixin is + added automatically to the built-in array. + + You should generally implement the `copy()` method to return a copy of the + receiver. + + Note that `frozenCopy()` will only work if you also implement + `Ember.Freezable`. + + @class Copyable + @namespace Ember + @since Ember 0.9 + */ + __exports__["default"] = Mixin.create({ + /** + Override to return a copy of the receiver. Default implementation raises + an exception. + + @method copy + @param {Boolean} deep if `true`, a deep copy of the object should be made + @return {Object} copy of receiver + */ + copy: required(Function), + + /** + If the object implements `Ember.Freezable`, then this will return a new + copy if the object is not frozen and the receiver if the object is frozen. + + Raises an exception if you try to call this method on a object that does + not support freezing. + + You should use this method whenever you want a copy of a freezable object + since a freezable object can simply return itself without actually + consuming more memory. + + @method frozenCopy + @return {Object} copy of receiver or receiver + */ + frozenCopy: function() { + if (Freezable && Freezable.detect(this)) { + return get(this, 'isFrozen') ? this : this.copy().freeze(); + } else { + throw new EmberError(fmt("%@ does not support freezing", [this])); + } + } + }); + }); +enifed("ember-runtime/mixins/deferred", + ["ember-metal/core","ember-metal/property_get","ember-metal/mixin","ember-metal/computed","ember-runtime/ext/rsvp","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.FEATURES, Ember.Test + var get = __dependency2__.get; + var Mixin = __dependency3__.Mixin; + var computed = __dependency4__.computed; + var RSVP = __dependency5__["default"]; + + /** + @module ember + @submodule ember-runtime + */ + + + /** + @class Deferred + @namespace Ember + */ + __exports__["default"] = Mixin.create({ + /** + Add handlers to be called when the Deferred object is resolved or rejected. + + @method then + @param {Function} resolve a callback function to be called when done + @param {Function} reject a callback function to be called when failed + */ + then: function(resolve, reject, label) { + var deferred, promise, entity; + + entity = this; + deferred = get(this, '_deferred'); + promise = deferred.promise; + + function fulfillmentHandler(fulfillment) { + if (fulfillment === promise) { + return resolve(entity); + } else { + return resolve(fulfillment); + } + } + + return promise.then(resolve && fulfillmentHandler, reject, label); + }, + + /** + Resolve a Deferred object and call any `doneCallbacks` with the given args. + + @method resolve + */ + resolve: function(value) { + var deferred, promise; + + deferred = get(this, '_deferred'); + promise = deferred.promise; + + if (value === this) { + deferred.resolve(promise); + } else { + deferred.resolve(value); + } + }, + + /** + Reject a Deferred object and call any `failCallbacks` with the given args. + + @method reject + */ + reject: function(value) { + get(this, '_deferred').reject(value); + }, + + _deferred: computed(function() { + Ember.deprecate('Usage of Ember.DeferredMixin or Ember.Deferred is deprecated.', this._suppressDeferredDeprecation); + + return RSVP.defer('Ember: DeferredMixin - ' + this); + }) + }); + }); +enifed("ember-runtime/mixins/enumerable", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/mixin","ember-metal/enumerable_utils","ember-metal/computed","ember-metal/property_events","ember-metal/events","ember-runtime/compare","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + // .......................................................... + // HELPERS + // + + var Ember = __dependency1__["default"]; + var get = __dependency2__.get; + var set = __dependency3__.set; + var apply = __dependency4__.apply; + var Mixin = __dependency5__.Mixin; + var required = __dependency5__.required; + var aliasMethod = __dependency5__.aliasMethod; + var indexOf = __dependency6__.indexOf; + var computed = __dependency7__.computed; + var propertyWillChange = __dependency8__.propertyWillChange; + var propertyDidChange = __dependency8__.propertyDidChange; + var addListener = __dependency9__.addListener; + var removeListener = __dependency9__.removeListener; + var sendEvent = __dependency9__.sendEvent; + var hasListeners = __dependency9__.hasListeners; + var compare = __dependency10__["default"]; + + var a_slice = Array.prototype.slice; + + var contexts = []; + + function popCtx() { + return contexts.length===0 ? {} : contexts.pop(); + } + + function pushCtx(ctx) { + contexts.push(ctx); + return null; + } + + function iter(key, value) { + var valueProvided = arguments.length === 2; + + function i(item) { + var cur = get(item, key); + return valueProvided ? value===cur : !!cur; + } + + return i; + } + + /** + This mixin defines the common interface implemented by enumerable objects + in Ember. Most of these methods follow the standard Array iteration + API defined up to JavaScript 1.8 (excluding language-specific features that + cannot be emulated in older versions of JavaScript). + + This mixin is applied automatically to the Array class on page load, so you + can use any of these methods on simple arrays. If Array already implements + one of these methods, the mixin will not override them. + + ## Writing Your Own Enumerable + + To make your own custom class enumerable, you need two items: + + 1. You must have a length property. This property should change whenever + the number of items in your enumerable object changes. If you use this + with an `Ember.Object` subclass, you should be sure to change the length + property using `set().` + + 2. You must implement `nextObject().` See documentation. + + Once you have these two methods implemented, apply the `Ember.Enumerable` mixin + to your class and you will be able to enumerate the contents of your object + like any other collection. + + ## Using Ember Enumeration with Other Libraries + + Many other libraries provide some kind of iterator or enumeration like + facility. This is often where the most common API conflicts occur. + Ember's API is designed to be as friendly as possible with other + libraries by implementing only methods that mostly correspond to the + JavaScript 1.8 API. + + @class Enumerable + @namespace Ember + @since Ember 0.9 + */ + __exports__["default"] = Mixin.create({ + + /** + Implement this method to make your class enumerable. + + This method will be call repeatedly during enumeration. The index value + will always begin with 0 and increment monotonically. You don't have to + rely on the index value to determine what object to return, but you should + always check the value and start from the beginning when you see the + requested index is 0. + + The `previousObject` is the object that was returned from the last call + to `nextObject` for the current iteration. This is a useful way to + manage iteration if you are tracing a linked list, for example. + + Finally the context parameter will always contain a hash you can use as + a "scratchpad" to maintain any other state you need in order to iterate + properly. The context object is reused and is not reset between + iterations so make sure you setup the context with a fresh state whenever + the index parameter is 0. + + Generally iterators will continue to call `nextObject` until the index + reaches the your current length-1. If you run out of data before this + time for some reason, you should simply return undefined. + + The default implementation of this method simply looks up the index. + This works great on any Array-like objects. + + @method nextObject + @param {Number} index the current index of the iteration + @param {Object} previousObject the value returned by the last call to + `nextObject`. + @param {Object} context a context object you can use to maintain state. + @return {Object} the next object in the iteration or undefined + */ + nextObject: required(Function), + + /** + Helper method returns the first object from a collection. This is usually + used by bindings and other parts of the framework to extract a single + object if the enumerable contains only one item. + + If you override this method, you should implement it so that it will + always return the same value each time it is called. If your enumerable + contains only one object, this method should always return that object. + If your enumerable is empty, this method should return `undefined`. + + ```javascript + var arr = ["a", "b", "c"]; + arr.get('firstObject'); // "a" + + var arr = []; + arr.get('firstObject'); // undefined + ``` + + @property firstObject + @return {Object} the object or undefined + */ + firstObject: computed('[]', function() { + if (get(this, 'length')===0) return undefined ; + + // handle generic enumerables + var context = popCtx(), ret; + ret = this.nextObject(0, null, context); + pushCtx(context); + return ret; + }), + + /** + Helper method returns the last object from a collection. If your enumerable + contains only one object, this method should always return that object. + If your enumerable is empty, this method should return `undefined`. + + ```javascript + var arr = ["a", "b", "c"]; + arr.get('lastObject'); // "c" + + var arr = []; + arr.get('lastObject'); // undefined + ``` + + @property lastObject + @return {Object} the last object or undefined + */ + lastObject: computed('[]', function() { + var len = get(this, 'length'); + if (len===0) return undefined ; + var context = popCtx(), idx=0, cur, last = null; + do { + last = cur; + cur = this.nextObject(idx++, last, context); + } while (cur !== undefined); + pushCtx(context); + return last; + }), + + /** + Returns `true` if the passed object can be found in the receiver. The + default version will iterate through the enumerable until the object + is found. You may want to override this with a more efficient version. + + ```javascript + var arr = ["a", "b", "c"]; + arr.contains("a"); // true + arr.contains("z"); // false + ``` + + @method contains + @param {Object} obj The object to search for. + @return {Boolean} `true` if object is found in enumerable. + */ + contains: function(obj) { + return this.find(function(item) { return item===obj; }) !== undefined; + }, + + /** + Iterates through the enumerable, calling the passed function on each + item. This method corresponds to the `forEach()` method defined in + JavaScript 1.6. + + The callback method you provide should have the following signature (all + parameters are optional): + + ```javascript + function(item, index, enumerable); + ``` + + - `item` is the current item in the iteration. + - `index` is the current index in the iteration. + - `enumerable` is the enumerable object itself. + + Note that in addition to a callback, you can also pass an optional target + object that will be set as `this` on the context. This is a good way + to give your iterator function access to the current object. + + @method forEach + @param {Function} callback The callback to execute + @param {Object} [target] The target object to use + @return {Object} receiver + */ + forEach: function(callback, target) { + if (typeof callback !== 'function') throw new TypeError() ; + var len = get(this, 'length'), last = null, context = popCtx(); + + if (target === undefined) target = null; + + for(var idx=0;idx1) args = a_slice.call(arguments, 1); + + this.forEach(function(x, idx) { + var method = x && x[methodName]; + if ('function' === typeof method) { + ret[idx] = args ? apply(x, method, args) : x[methodName](); + } + }, this); + + return ret; + }, + + /** + Simply converts the enumerable into a genuine array. The order is not + guaranteed. Corresponds to the method implemented by Prototype. + + @method toArray + @return {Array} the enumerable as an array. + */ + toArray: function() { + var ret = Ember.A(); + this.forEach(function(o, idx) { ret[idx] = o; }); + return ret; + }, + + /** + Returns a copy of the array with all null and undefined elements removed. + + ```javascript + var arr = ["a", null, "c", undefined]; + arr.compact(); // ["a", "c"] + ``` + + @method compact + @return {Array} the array without null and undefined elements. + */ + compact: function() { + return this.filter(function(value) { return value != null; }); + }, + + /** + Returns a new enumerable that excludes the passed value. The default + implementation returns an array regardless of the receiver type unless + the receiver does not contain the value. + + ```javascript + var arr = ["a", "b", "a", "c"]; + arr.without("a"); // ["b", "c"] + ``` + + @method without + @param {Object} value + @return {Ember.Enumerable} + */ + without: function(value) { + if (!this.contains(value)) return this; // nothing to do + var ret = Ember.A(); + this.forEach(function(k) { + if (k !== value) ret[ret.length] = k; + }) ; + return ret ; + }, + + /** + Returns a new enumerable that contains only unique values. The default + implementation returns an array regardless of the receiver type. + + ```javascript + var arr = ["a", "a", "b", "b"]; + arr.uniq(); // ["a", "b"] + ``` + + @method uniq + @return {Ember.Enumerable} + */ + uniq: function() { + var ret = Ember.A(); + this.forEach(function(k) { + if (indexOf(ret, k)<0) ret.push(k); + }); + return ret; + }, + + /** + This property will trigger anytime the enumerable's content changes. + You can observe this property to be notified of changes to the enumerables + content. + + For plain enumerables, this property is read only. `Array` overrides + this method. + + @property [] + @type Array + @return this + */ + '[]': computed(function(key, value) { + return this; + }), + + // .......................................................... + // ENUMERABLE OBSERVERS + // + + /** + Registers an enumerable observer. Must implement `Ember.EnumerableObserver` + mixin. + + @method addEnumerableObserver + @param {Object} target + @param {Hash} [opts] + @return this + */ + addEnumerableObserver: function(target, opts) { + var willChange = (opts && opts.willChange) || 'enumerableWillChange'; + var didChange = (opts && opts.didChange) || 'enumerableDidChange'; + var hasObservers = get(this, 'hasEnumerableObservers'); + + if (!hasObservers) propertyWillChange(this, 'hasEnumerableObservers'); + addListener(this, '@enumerable:before', target, willChange); + addListener(this, '@enumerable:change', target, didChange); + if (!hasObservers) propertyDidChange(this, 'hasEnumerableObservers'); + return this; + }, + + /** + Removes a registered enumerable observer. + + @method removeEnumerableObserver + @param {Object} target + @param {Hash} [opts] + @return this + */ + removeEnumerableObserver: function(target, opts) { + var willChange = (opts && opts.willChange) || 'enumerableWillChange'; + var didChange = (opts && opts.didChange) || 'enumerableDidChange'; + + var hasObservers = get(this, 'hasEnumerableObservers'); + if (hasObservers) propertyWillChange(this, 'hasEnumerableObservers'); + removeListener(this, '@enumerable:before', target, willChange); + removeListener(this, '@enumerable:change', target, didChange); + if (hasObservers) propertyDidChange(this, 'hasEnumerableObservers'); + return this; + }, + + /** + Becomes true whenever the array currently has observers watching changes + on the array. + + @property hasEnumerableObservers + @type Boolean + */ + hasEnumerableObservers: computed(function() { + return hasListeners(this, '@enumerable:change') || hasListeners(this, '@enumerable:before'); + }), + + + /** + Invoke this method just before the contents of your enumerable will + change. You can either omit the parameters completely or pass the objects + to be removed or added if available or just a count. + + @method enumerableContentWillChange + @param {Ember.Enumerable|Number} removing An enumerable of the objects to + be removed or the number of items to be removed. + @param {Ember.Enumerable|Number} adding An enumerable of the objects to be + added or the number of items to be added. + @chainable + */ + enumerableContentWillChange: function(removing, adding) { + + var removeCnt, addCnt, hasDelta; + + if ('number' === typeof removing) removeCnt = removing; + else if (removing) removeCnt = get(removing, 'length'); + else removeCnt = removing = -1; + + if ('number' === typeof adding) addCnt = adding; + else if (adding) addCnt = get(adding,'length'); + else addCnt = adding = -1; + + hasDelta = addCnt<0 || removeCnt<0 || addCnt-removeCnt!==0; + + if (removing === -1) removing = null; + if (adding === -1) adding = null; + + propertyWillChange(this, '[]'); + if (hasDelta) propertyWillChange(this, 'length'); + sendEvent(this, '@enumerable:before', [this, removing, adding]); + + return this; + }, + + /** + Invoke this method when the contents of your enumerable has changed. + This will notify any observers watching for content changes. If you are + implementing an ordered enumerable (such as an array), also pass the + start and end values where the content changed so that it can be used to + notify range observers. + + @method enumerableContentDidChange + @param {Ember.Enumerable|Number} removing An enumerable of the objects to + be removed or the number of items to be removed. + @param {Ember.Enumerable|Number} adding An enumerable of the objects to + be added or the number of items to be added. + @chainable + */ + enumerableContentDidChange: function(removing, adding) { + var removeCnt, addCnt, hasDelta; + + if ('number' === typeof removing) removeCnt = removing; + else if (removing) removeCnt = get(removing, 'length'); + else removeCnt = removing = -1; + + if ('number' === typeof adding) addCnt = adding; + else if (adding) addCnt = get(adding, 'length'); + else addCnt = adding = -1; + + hasDelta = addCnt<0 || removeCnt<0 || addCnt-removeCnt!==0; + + if (removing === -1) removing = null; + if (adding === -1) adding = null; + + sendEvent(this, '@enumerable:change', [this, removing, adding]); + if (hasDelta) propertyDidChange(this, 'length'); + propertyDidChange(this, '[]'); + + return this ; + }, + + /** + Converts the enumerable into an array and sorts by the keys + specified in the argument. + + You may provide multiple arguments to sort by multiple properties. + + @method sortBy + @param {String} property name(s) to sort on + @return {Array} The sorted array. + @since 1.2.0 + */ + sortBy: function() { + var sortKeys = arguments; + return this.toArray().sort(function(a, b){ + for(var i = 0; i < sortKeys.length; i++) { + var key = sortKeys[i]; + var propA = get(a, key); + var propB = get(b, key); + // return 1 or -1 else continue to the next sortKey + var compareValue = compare(propA, propB); + if (compareValue) { return compareValue; } + } + return 0; + }); + } + }); + }); +enifed("ember-runtime/mixins/evented", + ["ember-metal/mixin","ember-metal/events","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Mixin = __dependency1__.Mixin; + var addListener = __dependency2__.addListener; + var removeListener = __dependency2__.removeListener; + var hasListeners = __dependency2__.hasListeners; + var sendEvent = __dependency2__.sendEvent; + + /** + @module ember + @submodule ember-runtime + */ + + /** + This mixin allows for Ember objects to subscribe to and emit events. + + ```javascript + App.Person = Ember.Object.extend(Ember.Evented, { + greet: function() { + // ... + this.trigger('greet'); + } + }); + + var person = App.Person.create(); + + person.on('greet', function() { + console.log('Our person has greeted'); + }); + + person.greet(); + + // outputs: 'Our person has greeted' + ``` + + You can also chain multiple event subscriptions: + + ```javascript + person.on('greet', function() { + console.log('Our person has greeted'); + }).one('greet', function() { + console.log('Offer one-time special'); + }).off('event', this, forgetThis); + ``` + + @class Evented + @namespace Ember + */ + __exports__["default"] = Mixin.create({ + + /** + Subscribes to a named event with given function. + + ```javascript + person.on('didLoad', function() { + // fired once the person has loaded + }); + ``` + + An optional target can be passed in as the 2nd argument that will + be set as the "this" for the callback. This is a good way to give your + function access to the object triggering the event. When the target + parameter is used the callback becomes the third argument. + + @method on + @param {String} name The name of the event + @param {Object} [target] The "this" binding for the callback + @param {Function} method The callback to execute + @return this + */ + on: function(name, target, method) { + addListener(this, name, target, method); + return this; + }, + + /** + Subscribes a function to a named event and then cancels the subscription + after the first time the event is triggered. It is good to use ``one`` when + you only care about the first time an event has taken place. + + This function takes an optional 2nd argument that will become the "this" + value for the callback. If this argument is passed then the 3rd argument + becomes the function. + + @method one + @param {String} name The name of the event + @param {Object} [target] The "this" binding for the callback + @param {Function} method The callback to execute + @return this + */ + one: function(name, target, method) { + if (!method) { + method = target; + target = null; + } + + addListener(this, name, target, method, true); + return this; + }, + + /** + Triggers a named event for the object. Any additional arguments + will be passed as parameters to the functions that are subscribed to the + event. + + ```javascript + person.on('didEat', function(food) { + console.log('person ate some ' + food); + }); + + person.trigger('didEat', 'broccoli'); + + // outputs: person ate some broccoli + ``` + @method trigger + @param {String} name The name of the event + @param {Object...} args Optional arguments to pass on + */ + trigger: function(name) { + var length = arguments.length; + var args = new Array(length - 1); + + for (var i = 1; i < length; i++) { + args[i - 1] = arguments[i]; + } + + sendEvent(this, name, args); + }, + + /** + Cancels subscription for given name, target, and method. + + @method off + @param {String} name The name of the event + @param {Object} target The target of the subscription + @param {Function} method The function of the subscription + @return this + */ + off: function(name, target, method) { + removeListener(this, name, target, method); + return this; + }, + + /** + Checks to see if object has any subscriptions for named event. + + @method has + @param {String} name The name of the event + @return {Boolean} does the object have a subscription for event + */ + has: function(name) { + return hasListeners(this, name); + } + }); + }); +enifed("ember-runtime/mixins/freezable", + ["ember-metal/mixin","ember-metal/property_get","ember-metal/property_set","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Mixin = __dependency1__.Mixin; + var get = __dependency2__.get; + var set = __dependency3__.set; + + /** + The `Ember.Freezable` mixin implements some basic methods for marking an + object as frozen. Once an object is frozen it should be read only. No changes + may be made the internal state of the object. + + ## Enforcement + + To fully support freezing in your subclass, you must include this mixin and + override any method that might alter any property on the object to instead + raise an exception. You can check the state of an object by checking the + `isFrozen` property. + + Although future versions of JavaScript may support language-level freezing + object objects, that is not the case today. Even if an object is freezable, + it is still technically possible to modify the object, even though it could + break other parts of your application that do not expect a frozen object to + change. It is, therefore, very important that you always respect the + `isFrozen` property on all freezable objects. + + ## Example Usage + + The example below shows a simple object that implement the `Ember.Freezable` + protocol. + + ```javascript + Contact = Ember.Object.extend(Ember.Freezable, { + firstName: null, + lastName: null, + + // swaps the names + swapNames: function() { + if (this.get('isFrozen')) throw Ember.FROZEN_ERROR; + var tmp = this.get('firstName'); + this.set('firstName', this.get('lastName')); + this.set('lastName', tmp); + return this; + } + + }); + + c = Contact.create({ firstName: "John", lastName: "Doe" }); + c.swapNames(); // returns c + c.freeze(); + c.swapNames(); // EXCEPTION + ``` + + ## Copying + + Usually the `Ember.Freezable` protocol is implemented in cooperation with the + `Ember.Copyable` protocol, which defines a `frozenCopy()` method that will + return a frozen object, if the object implements this method as well. + + @class Freezable + @namespace Ember + @since Ember 0.9 + */ + var Freezable = Mixin.create({ + + /** + Set to `true` when the object is frozen. Use this property to detect + whether your object is frozen or not. + + @property isFrozen + @type Boolean + */ + isFrozen: false, + + /** + Freezes the object. Once this method has been called the object should + no longer allow any properties to be edited. + + @method freeze + @return {Object} receiver + */ + freeze: function() { + if (get(this, 'isFrozen')) return this; + set(this, 'isFrozen', true); + return this; + } + + }); + __exports__.Freezable = Freezable; + var FROZEN_ERROR = "Frozen object cannot be modified."; + __exports__.FROZEN_ERROR = FROZEN_ERROR; + }); +enifed("ember-runtime/mixins/mutable_array", + ["ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/error","ember-metal/mixin","ember-runtime/mixins/array","ember-runtime/mixins/mutable_enumerable","ember-runtime/mixins/enumerable","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + + // require('ember-runtime/mixins/array'); + // require('ember-runtime/mixins/mutable_enumerable'); + + // .......................................................... + // CONSTANTS + // + + var OUT_OF_RANGE_EXCEPTION = "Index out of range"; + var EMPTY = []; + + // .......................................................... + // HELPERS + // + + var get = __dependency1__.get; + var set = __dependency2__.set; + var isArray = __dependency3__.isArray; + var EmberError = __dependency4__["default"]; + var Mixin = __dependency5__.Mixin; + var required = __dependency5__.required; + var EmberArray = __dependency6__["default"]; + var MutableEnumerable = __dependency7__["default"]; + var Enumerable = __dependency8__["default"]; + /** + This mixin defines the API for modifying array-like objects. These methods + can be applied only to a collection that keeps its items in an ordered set. + It builds upon the Array mixin and adds methods to modify the array. + Concrete implementations of this class include ArrayProxy and ArrayController. + + It is important to use the methods in this class to modify arrays so that + changes are observable. This allows the binding system in Ember to function + correctly. + + + Note that an Array can change even if it does not implement this mixin. + For example, one might implement a SparseArray that cannot be directly + modified, but if its underlying enumerable changes, it will change also. + + @class MutableArray + @namespace Ember + @uses Ember.Array + @uses Ember.MutableEnumerable + */ + __exports__["default"] = Mixin.create(EmberArray, MutableEnumerable, { + + /** + __Required.__ You must implement this method to apply this mixin. + + This is one of the primitives you must implement to support `Ember.Array`. + You should replace amt objects started at idx with the objects in the + passed array. You should also call `this.enumerableContentDidChange()` + + @method replace + @param {Number} idx Starting index in the array to replace. If + idx >= length, then append to the end of the array. + @param {Number} amt Number of elements that should be removed from + the array, starting at *idx*. + @param {Array} objects An array of zero or more objects that should be + inserted into the array at *idx* + */ + replace: required(), + + /** + Remove all elements from the array. This is useful if you + want to reuse an existing array without having to recreate it. + + ```javascript + var colors = ["red", "green", "blue"]; + color.length(); // 3 + colors.clear(); // [] + colors.length(); // 0 + ``` + + @method clear + @return {Ember.Array} An empty Array. + */ + clear: function () { + var len = get(this, 'length'); + if (len === 0) return this; + this.replace(0, len, EMPTY); + return this; + }, + + /** + This will use the primitive `replace()` method to insert an object at the + specified index. + + ```javascript + var colors = ["red", "green", "blue"]; + colors.insertAt(2, "yellow"); // ["red", "green", "yellow", "blue"] + colors.insertAt(5, "orange"); // Error: Index out of range + ``` + + @method insertAt + @param {Number} idx index of insert the object at. + @param {Object} object object to insert + @return {Ember.Array} receiver + */ + insertAt: function(idx, object) { + if (idx > get(this, 'length')) throw new EmberError(OUT_OF_RANGE_EXCEPTION); + this.replace(idx, 0, [object]); + return this; + }, + + /** + Remove an object at the specified index using the `replace()` primitive + method. You can pass either a single index, or a start and a length. + + If you pass a start and length that is beyond the + length this method will throw an `OUT_OF_RANGE_EXCEPTION`. + + ```javascript + var colors = ["red", "green", "blue", "yellow", "orange"]; + colors.removeAt(0); // ["green", "blue", "yellow", "orange"] + colors.removeAt(2, 2); // ["green", "blue"] + colors.removeAt(4, 2); // Error: Index out of range + ``` + + @method removeAt + @param {Number} start index, start of range + @param {Number} len length of passing range + @return {Ember.Array} receiver + */ + removeAt: function(start, len) { + if ('number' === typeof start) { + + if ((start < 0) || (start >= get(this, 'length'))) { + throw new EmberError(OUT_OF_RANGE_EXCEPTION); + } + + // fast case + if (len === undefined) len = 1; + this.replace(start, len, EMPTY); + } + + return this; + }, + + /** + Push the object onto the end of the array. Works just like `push()` but it + is KVO-compliant. + + ```javascript + var colors = ["red", "green"]; + colors.pushObject("black"); // ["red", "green", "black"] + colors.pushObject(["yellow"]); // ["red", "green", ["yellow"]] + ``` + + @method pushObject + @param {*} obj object to push + @return object same object passed as a param + */ + pushObject: function(obj) { + this.insertAt(get(this, 'length'), obj); + return obj; + }, + + /** + Add the objects in the passed numerable to the end of the array. Defers + notifying observers of the change until all objects are added. + + ```javascript + var colors = ["red"]; + colors.pushObjects(["yellow", "orange"]); // ["red", "yellow", "orange"] + ``` + + @method pushObjects + @param {Ember.Enumerable} objects the objects to add + @return {Ember.Array} receiver + */ + pushObjects: function(objects) { + if (!(Enumerable.detect(objects) || isArray(objects))) { + throw new TypeError("Must pass Ember.Enumerable to Ember.MutableArray#pushObjects"); + } + this.replace(get(this, 'length'), 0, objects); + return this; + }, + + /** + Pop object from array or nil if none are left. Works just like `pop()` but + it is KVO-compliant. + + ```javascript + var colors = ["red", "green", "blue"]; + colors.popObject(); // "blue" + console.log(colors); // ["red", "green"] + ``` + + @method popObject + @return object + */ + popObject: function() { + var len = get(this, 'length'); + if (len === 0) return null; + + var ret = this.objectAt(len-1); + this.removeAt(len-1, 1); + return ret; + }, + + /** + Shift an object from start of array or nil if none are left. Works just + like `shift()` but it is KVO-compliant. + + ```javascript + var colors = ["red", "green", "blue"]; + colors.shiftObject(); // "red" + console.log(colors); // ["green", "blue"] + ``` + + @method shiftObject + @return object + */ + shiftObject: function() { + if (get(this, 'length') === 0) return null; + var ret = this.objectAt(0); + this.removeAt(0); + return ret; + }, + + /** + Unshift an object to start of array. Works just like `unshift()` but it is + KVO-compliant. + + ```javascript + var colors = ["red"]; + colors.unshiftObject("yellow"); // ["yellow", "red"] + colors.unshiftObject(["black"]); // [["black"], "yellow", "red"] + ``` + + @method unshiftObject + @param {*} obj object to unshift + @return object same object passed as a param + */ + unshiftObject: function(obj) { + this.insertAt(0, obj); + return obj; + }, + + /** + Adds the named objects to the beginning of the array. Defers notifying + observers until all objects have been added. + + ```javascript + var colors = ["red"]; + colors.unshiftObjects(["black", "white"]); // ["black", "white", "red"] + colors.unshiftObjects("yellow"); // Type Error: 'undefined' is not a function + ``` + + @method unshiftObjects + @param {Ember.Enumerable} objects the objects to add + @return {Ember.Array} receiver + */ + unshiftObjects: function(objects) { + this.replace(0, 0, objects); + return this; + }, + + /** + Reverse objects in the array. Works just like `reverse()` but it is + KVO-compliant. + + @method reverseObjects + @return {Ember.Array} receiver + */ + reverseObjects: function() { + var len = get(this, 'length'); + if (len === 0) return this; + var objects = this.toArray().reverse(); + this.replace(0, len, objects); + return this; + }, + + /** + Replace all the receiver's content with content of the argument. + If argument is an empty array receiver will be cleared. + + ```javascript + var colors = ["red", "green", "blue"]; + colors.setObjects(["black", "white"]); // ["black", "white"] + colors.setObjects([]); // [] + ``` + + @method setObjects + @param {Ember.Array} objects array whose content will be used for replacing + the content of the receiver + @return {Ember.Array} receiver with the new content + */ + setObjects: function(objects) { + if (objects.length === 0) return this.clear(); + + var len = get(this, 'length'); + this.replace(0, len, objects); + return this; + }, + + // .......................................................... + // IMPLEMENT Ember.MutableEnumerable + // + + /** + Remove all occurances of an object in the array. + + ```javascript + var cities = ["Chicago", "Berlin", "Lima", "Chicago"]; + cities.removeObject("Chicago"); // ["Berlin", "Lima"] + cities.removeObject("Lima"); // ["Berlin"] + cities.removeObject("Tokyo") // ["Berlin"] + ``` + + @method removeObject + @param {*} obj object to remove + @return {Ember.Array} receiver + */ + removeObject: function(obj) { + var loc = get(this, 'length') || 0; + while(--loc >= 0) { + var curObject = this.objectAt(loc); + if (curObject === obj) this.removeAt(loc); + } + return this; + }, + + /** + Push the object onto the end of the array if it is not already + present in the array. + + ```javascript + var cities = ["Chicago", "Berlin"]; + cities.addObject("Lima"); // ["Chicago", "Berlin", "Lima"] + cities.addObject("Berlin"); // ["Chicago", "Berlin", "Lima"] + ``` + + @method addObject + @param {*} obj object to add, if not already present + @return {Ember.Array} receiver + */ + addObject: function(obj) { + if (!this.contains(obj)) this.pushObject(obj); + return this; + } + + }); + }); +enifed("ember-runtime/mixins/mutable_enumerable", + ["ember-metal/enumerable_utils","ember-runtime/mixins/enumerable","ember-metal/mixin","ember-metal/property_events","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var forEach = __dependency1__.forEach; + var Enumerable = __dependency2__["default"]; + var Mixin = __dependency3__.Mixin; + var required = __dependency3__.required; + var beginPropertyChanges = __dependency4__.beginPropertyChanges; + var endPropertyChanges = __dependency4__.endPropertyChanges; + + /** + @module ember + @submodule ember-runtime + */ + + /** + This mixin defines the API for modifying generic enumerables. These methods + can be applied to an object regardless of whether it is ordered or + unordered. + + Note that an Enumerable can change even if it does not implement this mixin. + For example, a MappedEnumerable cannot be directly modified but if its + underlying enumerable changes, it will change also. + + ## Adding Objects + + To add an object to an enumerable, use the `addObject()` method. This + method will only add the object to the enumerable if the object is not + already present and is of a type supported by the enumerable. + + ```javascript + set.addObject(contact); + ``` + + ## Removing Objects + + To remove an object from an enumerable, use the `removeObject()` method. This + will only remove the object if it is present in the enumerable, otherwise + this method has no effect. + + ```javascript + set.removeObject(contact); + ``` + + ## Implementing In Your Own Code + + If you are implementing an object and want to support this API, just include + this mixin in your class and implement the required methods. In your unit + tests, be sure to apply the Ember.MutableEnumerableTests to your object. + + @class MutableEnumerable + @namespace Ember + @uses Ember.Enumerable + */ + __exports__["default"] = Mixin.create(Enumerable, { + + /** + __Required.__ You must implement this method to apply this mixin. + + Attempts to add the passed object to the receiver if the object is not + already present in the collection. If the object is present, this method + has no effect. + + If the passed object is of a type not supported by the receiver, + then this method should raise an exception. + + @method addObject + @param {Object} object The object to add to the enumerable. + @return {Object} the passed object + */ + addObject: required(Function), + + /** + Adds each object in the passed enumerable to the receiver. + + @method addObjects + @param {Ember.Enumerable} objects the objects to add. + @return {Object} receiver + */ + addObjects: function(objects) { + beginPropertyChanges(this); + forEach(objects, function(obj) { this.addObject(obj); }, this); + endPropertyChanges(this); + return this; + }, + + /** + __Required.__ You must implement this method to apply this mixin. + + Attempts to remove the passed object from the receiver collection if the + object is present in the collection. If the object is not present, + this method has no effect. + + If the passed object is of a type not supported by the receiver, + then this method should raise an exception. + + @method removeObject + @param {Object} object The object to remove from the enumerable. + @return {Object} the passed object + */ + removeObject: required(Function), + + + /** + Removes each object in the passed enumerable from the receiver. + + @method removeObjects + @param {Ember.Enumerable} objects the objects to remove + @return {Object} receiver + */ + removeObjects: function(objects) { + beginPropertyChanges(this); + for (var i = objects.length - 1; i >= 0; i--) { + this.removeObject(objects[i]); + } + endPropertyChanges(this); + return this; + } + }); + }); +enifed("ember-runtime/mixins/observable", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/get_properties","ember-metal/set_properties","ember-metal/mixin","ember-metal/events","ember-metal/property_events","ember-metal/observer","ember-metal/computed","ember-metal/is_none","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + var Ember = __dependency1__["default"]; + // Ember.assert + + var get = __dependency2__.get; + var getWithDefault = __dependency2__.getWithDefault; + var set = __dependency3__.set; + var apply = __dependency4__.apply; + var getProperties = __dependency5__["default"]; + var setProperties = __dependency6__["default"]; + var Mixin = __dependency7__.Mixin; + var hasListeners = __dependency8__.hasListeners; + var beginPropertyChanges = __dependency9__.beginPropertyChanges; + var propertyWillChange = __dependency9__.propertyWillChange; + var propertyDidChange = __dependency9__.propertyDidChange; + var endPropertyChanges = __dependency9__.endPropertyChanges; + var addObserver = __dependency10__.addObserver; + var addBeforeObserver = __dependency10__.addBeforeObserver; + var removeObserver = __dependency10__.removeObserver; + var observersFor = __dependency10__.observersFor; + var cacheFor = __dependency11__.cacheFor; + var isNone = __dependency12__.isNone; + + + var slice = Array.prototype.slice; + /** + ## Overview + + This mixin provides properties and property observing functionality, core + features of the Ember object model. + + Properties and observers allow one object to observe changes to a + property on another object. This is one of the fundamental ways that + models, controllers and views communicate with each other in an Ember + application. + + Any object that has this mixin applied can be used in observer + operations. That includes `Ember.Object` and most objects you will + interact with as you write your Ember application. + + Note that you will not generally apply this mixin to classes yourself, + but you will use the features provided by this module frequently, so it + is important to understand how to use it. + + ## Using `get()` and `set()` + + Because of Ember's support for bindings and observers, you will always + access properties using the get method, and set properties using the + set method. This allows the observing objects to be notified and + computed properties to be handled properly. + + More documentation about `get` and `set` are below. + + ## Observing Property Changes + + You typically observe property changes simply by adding the `observes` + call to the end of your method declarations in classes that you write. + For example: + + ```javascript + Ember.Object.extend({ + valueObserver: function() { + // Executes whenever the "value" property changes + }.observes('value') + }); + ``` + + Although this is the most common way to add an observer, this capability + is actually built into the `Ember.Object` class on top of two methods + defined in this mixin: `addObserver` and `removeObserver`. You can use + these two methods to add and remove observers yourself if you need to + do so at runtime. + + To add an observer for a property, call: + + ```javascript + object.addObserver('propertyKey', targetObject, targetAction) + ``` + + This will call the `targetAction` method on the `targetObject` whenever + the value of the `propertyKey` changes. + + Note that if `propertyKey` is a computed property, the observer will be + called when any of the property dependencies are changed, even if the + resulting value of the computed property is unchanged. This is necessary + because computed properties are not computed until `get` is called. + + @class Observable + @namespace Ember + */ + __exports__["default"] = Mixin.create({ + + /** + Retrieves the value of a property from the object. + + This method is usually similar to using `object[keyName]` or `object.keyName`, + however it supports both computed properties and the unknownProperty + handler. + + Because `get` unifies the syntax for accessing all these kinds + of properties, it can make many refactorings easier, such as replacing a + simple property with a computed property, or vice versa. + + ### Computed Properties + + Computed properties are methods defined with the `property` modifier + declared at the end, such as: + + ```javascript + fullName: function() { + return this.get('firstName') + ' ' + this.get('lastName'); + }.property('firstName', 'lastName') + ``` + + When you call `get` on a computed property, the function will be + called and the return value will be returned instead of the function + itself. + + ### Unknown Properties + + Likewise, if you try to call `get` on a property whose value is + `undefined`, the `unknownProperty()` method will be called on the object. + If this method returns any value other than `undefined`, it will be returned + instead. This allows you to implement "virtual" properties that are + not defined upfront. + + @method get + @param {String} keyName The property to retrieve + @return {Object} The property value or undefined. + */ + get: function(keyName) { + return get(this, keyName); + }, + + /** + To get the values of multiple properties at once, call `getProperties` + with a list of strings or an array: + + ```javascript + record.getProperties('firstName', 'lastName', 'zipCode'); + // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } + ``` + + is equivalent to: + + ```javascript + record.getProperties(['firstName', 'lastName', 'zipCode']); + // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } + ``` + + @method getProperties + @param {String...|Array} list of keys to get + @return {Hash} + */ + getProperties: function() { + return apply(null, getProperties, [this].concat(slice.call(arguments))); + }, + + /** + Sets the provided key or path to the value. + + This method is generally very similar to calling `object[key] = value` or + `object.key = value`, except that it provides support for computed + properties, the `setUnknownProperty()` method and property observers. + + ### Computed Properties + + If you try to set a value on a key that has a computed property handler + defined (see the `get()` method for an example), then `set()` will call + that method, passing both the value and key instead of simply changing + the value itself. This is useful for those times when you need to + implement a property that is composed of one or more member + properties. + + ### Unknown Properties + + If you try to set a value on a key that is undefined in the target + object, then the `setUnknownProperty()` handler will be called instead. This + gives you an opportunity to implement complex "virtual" properties that + are not predefined on the object. If `setUnknownProperty()` returns + undefined, then `set()` will simply set the value on the object. + + ### Property Observers + + In addition to changing the property, `set()` will also register a property + change with the object. Unless you have placed this call inside of a + `beginPropertyChanges()` and `endPropertyChanges(),` any "local" observers + (i.e. observer methods declared on the same object), will be called + immediately. Any "remote" observers (i.e. observer methods declared on + another object) will be placed in a queue and called at a later time in a + coalesced manner. + + ### Chaining + + In addition to property changes, `set()` returns the value of the object + itself so you can do chaining like this: + + ```javascript + record.set('firstName', 'Charles').set('lastName', 'Jolley'); + ``` + + @method set + @param {String} keyName The property to set + @param {Object} value The value to set or `null`. + @return {Ember.Observable} + */ + set: function(keyName, value) { + set(this, keyName, value); + return this; + }, + + + /** + Sets a list of properties at once. These properties are set inside + a single `beginPropertyChanges` and `endPropertyChanges` batch, so + observers will be buffered. + + ```javascript + record.setProperties({ firstName: 'Charles', lastName: 'Jolley' }); + ``` + + @method setProperties + @param {Hash} hash the hash of keys and values to set + @return {Ember.Observable} + */ + setProperties: function(hash) { + return setProperties(this, hash); + }, + + /** + Begins a grouping of property changes. + + You can use this method to group property changes so that notifications + will not be sent until the changes are finished. If you plan to make a + large number of changes to an object at one time, you should call this + method at the beginning of the changes to begin deferring change + notifications. When you are done making changes, call + `endPropertyChanges()` to deliver the deferred change notifications and end + deferring. + + @method beginPropertyChanges + @return {Ember.Observable} + */ + beginPropertyChanges: function() { + beginPropertyChanges(); + return this; + }, + + /** + Ends a grouping of property changes. + + You can use this method to group property changes so that notifications + will not be sent until the changes are finished. If you plan to make a + large number of changes to an object at one time, you should call + `beginPropertyChanges()` at the beginning of the changes to defer change + notifications. When you are done making changes, call this method to + deliver the deferred change notifications and end deferring. + + @method endPropertyChanges + @return {Ember.Observable} + */ + endPropertyChanges: function() { + endPropertyChanges(); + return this; + }, + + /** + Notify the observer system that a property is about to change. + + Sometimes you need to change a value directly or indirectly without + actually calling `get()` or `set()` on it. In this case, you can use this + method and `propertyDidChange()` instead. Calling these two methods + together will notify all observers that the property has potentially + changed value. + + Note that you must always call `propertyWillChange` and `propertyDidChange` + as a pair. If you do not, it may get the property change groups out of + order and cause notifications to be delivered more often than you would + like. + + @method propertyWillChange + @param {String} keyName The property key that is about to change. + @return {Ember.Observable} + */ + propertyWillChange: function(keyName) { + propertyWillChange(this, keyName); + return this; + }, + + /** + Notify the observer system that a property has just changed. + + Sometimes you need to change a value directly or indirectly without + actually calling `get()` or `set()` on it. In this case, you can use this + method and `propertyWillChange()` instead. Calling these two methods + together will notify all observers that the property has potentially + changed value. + + Note that you must always call `propertyWillChange` and `propertyDidChange` + as a pair. If you do not, it may get the property change groups out of + order and cause notifications to be delivered more often than you would + like. + + @method propertyDidChange + @param {String} keyName The property key that has just changed. + @return {Ember.Observable} + */ + propertyDidChange: function(keyName) { + propertyDidChange(this, keyName); + return this; + }, + + /** + Convenience method to call `propertyWillChange` and `propertyDidChange` in + succession. + + @method notifyPropertyChange + @param {String} keyName The property key to be notified about. + @return {Ember.Observable} + */ + notifyPropertyChange: function(keyName) { + this.propertyWillChange(keyName); + this.propertyDidChange(keyName); + return this; + }, + + addBeforeObserver: function(key, target, method) { + addBeforeObserver(this, key, target, method); + }, + + /** + Adds an observer on a property. + + This is the core method used to register an observer for a property. + + Once you call this method, any time the key's value is set, your observer + will be notified. Note that the observers are triggered any time the + value is set, regardless of whether it has actually changed. Your + observer should be prepared to handle that. + + You can also pass an optional context parameter to this method. The + context will be passed to your observer method whenever it is triggered. + Note that if you add the same target/method pair on a key multiple times + with different context parameters, your observer will only be called once + with the last context you passed. + + ### Observer Methods + + Observer methods you pass should generally have the following signature if + you do not pass a `context` parameter: + + ```javascript + fooDidChange: function(sender, key, value, rev) { }; + ``` + + The sender is the object that changed. The key is the property that + changes. The value property is currently reserved and unused. The rev + is the last property revision of the object when it changed, which you can + use to detect if the key value has really changed or not. + + If you pass a `context` parameter, the context will be passed before the + revision like so: + + ```javascript + fooDidChange: function(sender, key, value, context, rev) { }; + ``` + + Usually you will not need the value, context or revision parameters at + the end. In this case, it is common to write observer methods that take + only a sender and key value as parameters or, if you aren't interested in + any of these values, to write an observer that has no parameters at all. + + @method addObserver + @param {String} key The key to observer + @param {Object} target The target object to invoke + @param {String|Function} method The method to invoke. + */ + addObserver: function(key, target, method) { + addObserver(this, key, target, method); + }, + + /** + Remove an observer you have previously registered on this object. Pass + the same key, target, and method you passed to `addObserver()` and your + target will no longer receive notifications. + + @method removeObserver + @param {String} key The key to observer + @param {Object} target The target object to invoke + @param {String|Function} method The method to invoke. + */ + removeObserver: function(key, target, method) { + removeObserver(this, key, target, method); + }, + + /** + Returns `true` if the object currently has observers registered for a + particular key. You can use this method to potentially defer performing + an expensive action until someone begins observing a particular property + on the object. + + @method hasObserverFor + @param {String} key Key to check + @return {Boolean} + */ + hasObserverFor: function(key) { + return hasListeners(this, key+':change'); + }, + + /** + Retrieves the value of a property, or a default value in the case that the + property returns `undefined`. + + ```javascript + person.getWithDefault('lastName', 'Doe'); + ``` + + @method getWithDefault + @param {String} keyName The name of the property to retrieve + @param {Object} defaultValue The value to return if the property value is undefined + @return {Object} The property value or the defaultValue. + */ + getWithDefault: function(keyName, defaultValue) { + return getWithDefault(this, keyName, defaultValue); + }, + + /** + Set the value of a property to the current value plus some amount. + + ```javascript + person.incrementProperty('age'); + team.incrementProperty('score', 2); + ``` + + @method incrementProperty + @param {String} keyName The name of the property to increment + @param {Number} increment The amount to increment by. Defaults to 1 + @return {Number} The new property value + */ + incrementProperty: function(keyName, increment) { + if (isNone(increment)) { increment = 1; } + Ember.assert("Must pass a numeric value to incrementProperty", (!isNaN(parseFloat(increment)) && isFinite(increment))); + set(this, keyName, (parseFloat(get(this, keyName)) || 0) + increment); + return get(this, keyName); + }, + + /** + Set the value of a property to the current value minus some amount. + + ```javascript + player.decrementProperty('lives'); + orc.decrementProperty('health', 5); + ``` + + @method decrementProperty + @param {String} keyName The name of the property to decrement + @param {Number} decrement The amount to decrement by. Defaults to 1 + @return {Number} The new property value + */ + decrementProperty: function(keyName, decrement) { + if (isNone(decrement)) { decrement = 1; } + Ember.assert("Must pass a numeric value to decrementProperty", (!isNaN(parseFloat(decrement)) && isFinite(decrement))); + set(this, keyName, (get(this, keyName) || 0) - decrement); + return get(this, keyName); + }, + + /** + Set the value of a boolean property to the opposite of it's + current value. + + ```javascript + starship.toggleProperty('warpDriveEngaged'); + ``` + + @method toggleProperty + @param {String} keyName The name of the property to toggle + @return {Object} The new property value + */ + toggleProperty: function(keyName) { + set(this, keyName, !get(this, keyName)); + return get(this, keyName); + }, + + /** + Returns the cached value of a computed property, if it exists. + This allows you to inspect the value of a computed property + without accidentally invoking it if it is intended to be + generated lazily. + + @method cacheFor + @param {String} keyName + @return {Object} The cached value of the computed property, if any + */ + cacheFor: function(keyName) { + return cacheFor(this, keyName); + }, + + // intended for debugging purposes + observersForKey: function(keyName) { + return observersFor(this, keyName); + } + }); + }); +enifed("ember-runtime/mixins/promise_proxy", + ["ember-metal/property_get","ember-metal/set_properties","ember-metal/computed","ember-metal/mixin","ember-metal/error","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var setProperties = __dependency2__["default"]; + var computed = __dependency3__.computed; + var Mixin = __dependency4__.Mixin; + var EmberError = __dependency5__["default"]; + + var not = computed.not; + var or = computed.or; + + /** + @module ember + @submodule ember-runtime + */ + + function tap(proxy, promise) { + setProperties(proxy, { + isFulfilled: false, + isRejected: false + }); + + return promise.then(function(value) { + setProperties(proxy, { + content: value, + isFulfilled: true + }); + return value; + }, function(reason) { + setProperties(proxy, { + reason: reason, + isRejected: true + }); + throw reason; + }, "Ember: PromiseProxy"); + } + + /** + A low level mixin making ObjectProxy, ObjectController or ArrayController's promise aware. + + ```javascript + var ObjectPromiseController = Ember.ObjectController.extend(Ember.PromiseProxyMixin); + + var controller = ObjectPromiseController.create({ + promise: $.getJSON('/some/remote/data.json') + }); + + controller.then(function(json){ + // the json + }, function(reason) { + // the reason why you have no json + }); + ``` + + the controller has bindable attributes which + track the promises life cycle + + ```javascript + controller.get('isPending') //=> true + controller.get('isSettled') //=> false + controller.get('isRejected') //=> false + controller.get('isFulfilled') //=> false + ``` + + When the the $.getJSON completes, and the promise is fulfilled + with json, the life cycle attributes will update accordingly. + + ```javascript + controller.get('isPending') //=> false + controller.get('isSettled') //=> true + controller.get('isRejected') //=> false + controller.get('isFulfilled') //=> true + ``` + + As the controller is an ObjectController, and the json now its content, + all the json properties will be available directly from the controller. + + ```javascript + // Assuming the following json: + { + firstName: 'Stefan', + lastName: 'Penner' + } + + // both properties will accessible on the controller + controller.get('firstName') //=> 'Stefan' + controller.get('lastName') //=> 'Penner' + ``` + + If the controller is backing a template, the attributes are + bindable from within that template + + ```handlebars + {{#if isPending}} + loading... + {{else}} + firstName: {{firstName}} + lastName: {{lastName}} + {{/if}} + ``` + @class Ember.PromiseProxyMixin + */ + __exports__["default"] = Mixin.create({ + /** + If the proxied promise is rejected this will contain the reason + provided. + + @property reason + @default null + */ + reason: null, + + /** + Once the proxied promise has settled this will become `false`. + + @property isPending + @default true + */ + isPending: not('isSettled').readOnly(), + + /** + Once the proxied promise has settled this will become `true`. + + @property isSettled + @default false + */ + isSettled: or('isRejected', 'isFulfilled').readOnly(), + + /** + Will become `true` if the proxied promise is rejected. + + @property isRejected + @default false + */ + isRejected: false, + + /** + Will become `true` if the proxied promise is fulfilled. + + @property isFulfilled + @default false + */ + isFulfilled: false, + + /** + The promise whose fulfillment value is being proxied by this object. + + This property must be specified upon creation, and should not be + changed once created. + + Example: + + ```javascript + Ember.ObjectController.extend(Ember.PromiseProxyMixin).create({ + promise: + }); + ``` + + @property promise + */ + promise: computed(function(key, promise) { + if (arguments.length === 2) { + return tap(this, promise); + } else { + throw new EmberError("PromiseProxy's promise must be set"); + } + }), + + /** + An alias to the proxied promise's `then`. + + See RSVP.Promise.then. + + @method then + @param {Function} callback + @return {RSVP.Promise} + */ + then: promiseAlias('then'), + + /** + An alias to the proxied promise's `catch`. + + See RSVP.Promise.catch. + + @method catch + @param {Function} callback + @return {RSVP.Promise} + @since 1.3.0 + */ + 'catch': promiseAlias('catch'), + + /** + An alias to the proxied promise's `finally`. + + See RSVP.Promise.finally. + + @method finally + @param {Function} callback + @return {RSVP.Promise} + @since 1.3.0 + */ + 'finally': promiseAlias('finally') + + }); + + function promiseAlias(name) { + return function () { + var promise = get(this, 'promise'); + return promise[name].apply(promise, arguments); + }; + } + }); +enifed("ember-runtime/mixins/sortable", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/enumerable_utils","ember-metal/mixin","ember-runtime/mixins/mutable_enumerable","ember-runtime/compare","ember-metal/observer","ember-metal/computed","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + // Ember.assert, Ember.A + + var get = __dependency2__.get; + var set = __dependency3__.set; + var forEach = __dependency4__.forEach; + var Mixin = __dependency5__.Mixin; + var MutableEnumerable = __dependency6__["default"]; + var compare = __dependency7__["default"]; + var addObserver = __dependency8__.addObserver; + var removeObserver = __dependency8__.removeObserver; + var computed = __dependency9__.computed; + var beforeObserver = __dependency5__.beforeObserver; + var observer = __dependency5__.observer; + //ES6TODO: should we access these directly from their package or from how thier exposed in ember-metal? + + /** + `Ember.SortableMixin` provides a standard interface for array proxies + to specify a sort order and maintain this sorting when objects are added, + removed, or updated without changing the implicit order of their underlying + modelarray: + + ```javascript + songs = [ + {trackNumber: 4, title: 'Ob-La-Di, Ob-La-Da'}, + {trackNumber: 2, title: 'Back in the U.S.S.R.'}, + {trackNumber: 3, title: 'Glass Onion'}, + ]; + + songsController = Ember.ArrayController.create({ + model: songs, + sortProperties: ['trackNumber'], + sortAscending: true + }); + + songsController.get('firstObject'); // {trackNumber: 2, title: 'Back in the U.S.S.R.'} + + songsController.addObject({trackNumber: 1, title: 'Dear Prudence'}); + songsController.get('firstObject'); // {trackNumber: 1, title: 'Dear Prudence'} + ``` + + If you add or remove the properties to sort by or change the sort direction the model + sort order will be automatically updated. + + ```javascript + songsController.set('sortProperties', ['title']); + songsController.get('firstObject'); // {trackNumber: 2, title: 'Back in the U.S.S.R.'} + + songsController.toggleProperty('sortAscending'); + songsController.get('firstObject'); // {trackNumber: 4, title: 'Ob-La-Di, Ob-La-Da'} + ``` + + SortableMixin works by sorting the arrangedContent array, which is the array that + arrayProxy displays. Due to the fact that the underlying 'content' array is not changed, that + array will not display the sorted list: + + ```javascript + songsController.get('content').get('firstObject'); // Returns the unsorted original content + songsController.get('firstObject'); // Returns the sorted content. + ``` + + Although the sorted content can also be accessed through the arrangedContent property, + it is preferable to use the proxied class and not the arrangedContent array directly. + + @class SortableMixin + @namespace Ember + @uses Ember.MutableEnumerable + */ + __exports__["default"] = Mixin.create(MutableEnumerable, { + + /** + Specifies which properties dictate the arrangedContent's sort order. + + When specifying multiple properties the sorting will use properties + from the `sortProperties` array prioritized from first to last. + + @property {Array} sortProperties + */ + sortProperties: null, + + /** + Specifies the arrangedContent's sort direction. + Sorts the content in ascending order by default. Set to `false` to + use descending order. + + @property {Boolean} sortAscending + @default true + */ + sortAscending: true, + + /** + The function used to compare two values. You can override this if you + want to do custom comparisons. Functions must be of the type expected by + Array#sort, i.e. + return 0 if the two parameters are equal, + return a negative value if the first parameter is smaller than the second or + return a positive value otherwise: + + ```javascript + function(x,y) { // These are assumed to be integers + if (x === y) + return 0; + return x < y ? -1 : 1; + } + ``` + + @property sortFunction + @type {Function} + @default Ember.compare + */ + sortFunction: compare, + + orderBy: function(item1, item2) { + var result = 0; + var sortProperties = get(this, 'sortProperties'); + var sortAscending = get(this, 'sortAscending'); + var sortFunction = get(this, 'sortFunction'); + + Ember.assert("you need to define `sortProperties`", !!sortProperties); + + forEach(sortProperties, function(propertyName) { + if (result === 0) { + result = sortFunction.call(this, get(item1, propertyName), get(item2, propertyName)); + if ((result !== 0) && !sortAscending) { + result = (-1) * result; + } + } + }, this); + + return result; + }, + + destroy: function() { + var content = get(this, 'content'); + var sortProperties = get(this, 'sortProperties'); + + if (content && sortProperties) { + forEach(content, function(item) { + forEach(sortProperties, function(sortProperty) { + removeObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + } + + return this._super(); + }, + + isSorted: computed.notEmpty('sortProperties'), + + /** + Overrides the default arrangedContent from arrayProxy in order to sort by sortFunction. + Also sets up observers for each sortProperty on each item in the content Array. + + @property arrangedContent + */ + + arrangedContent: computed('content', 'sortProperties.@each', function(key, value) { + var content = get(this, 'content'); + var isSorted = get(this, 'isSorted'); + var sortProperties = get(this, 'sortProperties'); + var self = this; + + if (content && isSorted) { + content = content.slice(); + content.sort(function(item1, item2) { + return self.orderBy(item1, item2); + }); + forEach(content, function(item) { + forEach(sortProperties, function(sortProperty) { + addObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + return Ember.A(content); + } + + return content; + }), + + _contentWillChange: beforeObserver('content', function() { + var content = get(this, 'content'); + var sortProperties = get(this, 'sortProperties'); + + if (content && sortProperties) { + forEach(content, function(item) { + forEach(sortProperties, function(sortProperty) { + removeObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + } + + this._super(); + }), + + sortPropertiesWillChange: beforeObserver('sortProperties', function() { + this._lastSortAscending = undefined; + }), + + sortPropertiesDidChange: observer('sortProperties', function() { + this._lastSortAscending = undefined; + }), + + sortAscendingWillChange: beforeObserver('sortAscending', function() { + this._lastSortAscending = get(this, 'sortAscending'); + }), + + sortAscendingDidChange: observer('sortAscending', function() { + if (this._lastSortAscending !== undefined && get(this, 'sortAscending') !== this._lastSortAscending) { + var arrangedContent = get(this, 'arrangedContent'); + arrangedContent.reverseObjects(); + } + }), + + contentArrayWillChange: function(array, idx, removedCount, addedCount) { + var isSorted = get(this, 'isSorted'); + + if (isSorted) { + var arrangedContent = get(this, 'arrangedContent'); + var removedObjects = array.slice(idx, idx+removedCount); + var sortProperties = get(this, 'sortProperties'); + + forEach(removedObjects, function(item) { + arrangedContent.removeObject(item); + + forEach(sortProperties, function(sortProperty) { + removeObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + } + + return this._super(array, idx, removedCount, addedCount); + }, + + contentArrayDidChange: function(array, idx, removedCount, addedCount) { + var isSorted = get(this, 'isSorted'); + var sortProperties = get(this, 'sortProperties'); + + if (isSorted) { + var addedObjects = array.slice(idx, idx+addedCount); + + forEach(addedObjects, function(item) { + this.insertItemSorted(item); + + forEach(sortProperties, function(sortProperty) { + addObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + } + + return this._super(array, idx, removedCount, addedCount); + }, + + insertItemSorted: function(item) { + var arrangedContent = get(this, 'arrangedContent'); + var length = get(arrangedContent, 'length'); + + var idx = this._binarySearch(item, 0, length); + arrangedContent.insertAt(idx, item); + }, + + contentItemSortPropertyDidChange: function(item) { + var arrangedContent = get(this, 'arrangedContent'); + var oldIndex = arrangedContent.indexOf(item); + var leftItem = arrangedContent.objectAt(oldIndex - 1); + var rightItem = arrangedContent.objectAt(oldIndex + 1); + var leftResult = leftItem && this.orderBy(item, leftItem); + var rightResult = rightItem && this.orderBy(item, rightItem); + + if (leftResult < 0 || rightResult > 0) { + arrangedContent.removeObject(item); + this.insertItemSorted(item); + } + }, + + _binarySearch: function(item, low, high) { + var mid, midItem, res, arrangedContent; + + if (low === high) { + return low; + } + + arrangedContent = get(this, 'arrangedContent'); + + mid = low + Math.floor((high - low) / 2); + midItem = arrangedContent.objectAt(mid); + + res = this.orderBy(midItem, item); + + if (res < 0) { + return this._binarySearch(item, mid+1, high); + } else if (res > 0) { + return this._binarySearch(item, low, mid); + } + + return mid; + } + }); + }); +enifed("ember-runtime/mixins/target_action_support", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/mixin","ember-metal/computed","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + var Ember = __dependency1__["default"]; + // Ember.lookup, Ember.assert + + var get = __dependency2__.get; + var set = __dependency3__.set; + var typeOf = __dependency4__.typeOf; + var Mixin = __dependency5__.Mixin; + var computed = __dependency6__.computed; + + /** + `Ember.TargetActionSupport` is a mixin that can be included in a class + to add a `triggerAction` method with semantics similar to the Handlebars + `{{action}}` helper. In normal Ember usage, the `{{action}}` helper is + usually the best choice. This mixin is most often useful when you are + doing more complex event handling in View objects. + + See also `Ember.ViewTargetActionSupport`, which has + view-aware defaults for target and actionContext. + + @class TargetActionSupport + @namespace Ember + @extends Ember.Mixin + */ + var TargetActionSupport = Mixin.create({ + target: null, + action: null, + actionContext: null, + + targetObject: computed(function() { + var target = get(this, 'target'); + + if (typeOf(target) === "string") { + var value = get(this, target); + if (value === undefined) { value = get(Ember.lookup, target); } + return value; + } else { + return target; + } + }).property('target'), + + actionContextObject: computed(function() { + var actionContext = get(this, 'actionContext'); + + if (typeOf(actionContext) === "string") { + var value = get(this, actionContext); + if (value === undefined) { value = get(Ember.lookup, actionContext); } + return value; + } else { + return actionContext; + } + }).property('actionContext'), + + /** + Send an `action` with an `actionContext` to a `target`. The action, actionContext + and target will be retrieved from properties of the object. For example: + + ```javascript + App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, { + target: Ember.computed.alias('controller'), + action: 'save', + actionContext: Ember.computed.alias('context'), + click: function() { + this.triggerAction(); // Sends the `save` action, along with the current context + // to the current controller + } + }); + ``` + + The `target`, `action`, and `actionContext` can be provided as properties of + an optional object argument to `triggerAction` as well. + + ```javascript + App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, { + click: function() { + this.triggerAction({ + action: 'save', + target: this.get('controller'), + actionContext: this.get('context') + }); // Sends the `save` action, along with the current context + // to the current controller + } + }); + ``` + + The `actionContext` defaults to the object you are mixing `TargetActionSupport` into. + But `target` and `action` must be specified either as properties or with the argument + to `triggerAction`, or a combination: + + ```javascript + App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, { + target: Ember.computed.alias('controller'), + click: function() { + this.triggerAction({ + action: 'save' + }); // Sends the `save` action, along with a reference to `this`, + // to the current controller + } + }); + ``` + + @method triggerAction + @param opts {Hash} (optional, with the optional keys action, target and/or actionContext) + @return {Boolean} true if the action was sent successfully and did not return false + */ + triggerAction: function(opts) { + opts = opts || {}; + var action = opts.action || get(this, 'action'); + var target = opts.target || get(this, 'targetObject'); + var actionContext = opts.actionContext; + + function args(options, actionName) { + var ret = []; + if (actionName) { ret.push(actionName); } + + return ret.concat(options); + } + + if (typeof actionContext === 'undefined') { + actionContext = get(this, 'actionContextObject') || this; + } + + if (target && action) { + var ret; + + if (target.send) { + ret = target.send.apply(target, args(actionContext, action)); + } else { + Ember.assert("The action '" + action + "' did not exist on " + target, typeof target[action] === 'function'); + ret = target[action].apply(target, args(actionContext)); + } + + if (ret !== false) ret = true; + + return ret; + } else { + return false; + } + } + }); + + __exports__["default"] = TargetActionSupport; + }); +enifed("ember-runtime/system/application", + ["ember-runtime/system/namespace","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Namespace = __dependency1__["default"]; + + __exports__["default"] = Namespace.extend(); + }); +enifed("ember-runtime/system/array_proxy", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/computed","ember-metal/mixin","ember-metal/property_events","ember-metal/error","ember-runtime/system/object","ember-runtime/mixins/mutable_array","ember-runtime/mixins/enumerable","ember-runtime/system/string","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.K, Ember.assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var isArray = __dependency4__.isArray; + var apply = __dependency4__.apply; + var computed = __dependency5__.computed; + var beforeObserver = __dependency6__.beforeObserver; + var observer = __dependency6__.observer; + var beginPropertyChanges = __dependency7__.beginPropertyChanges; + var endPropertyChanges = __dependency7__.endPropertyChanges; + var EmberError = __dependency8__["default"]; + var EmberObject = __dependency9__["default"]; + var MutableArray = __dependency10__["default"]; + var Enumerable = __dependency11__["default"]; + var fmt = __dependency12__.fmt; + + /** + @module ember + @submodule ember-runtime + */ + + var OUT_OF_RANGE_EXCEPTION = "Index out of range"; + var EMPTY = []; + var alias = computed.alias; + var K = Ember.K; + + /** + An ArrayProxy wraps any other object that implements `Ember.Array` and/or + `Ember.MutableArray,` forwarding all requests. This makes it very useful for + a number of binding use cases or other cases where being able to swap + out the underlying array is useful. + + A simple example of usage: + + ```javascript + var pets = ['dog', 'cat', 'fish']; + var ap = Ember.ArrayProxy.create({ content: Ember.A(pets) }); + + ap.get('firstObject'); // 'dog' + ap.set('content', ['amoeba', 'paramecium']); + ap.get('firstObject'); // 'amoeba' + ``` + + This class can also be useful as a layer to transform the contents of + an array, as they are accessed. This can be done by overriding + `objectAtContent`: + + ```javascript + var pets = ['dog', 'cat', 'fish']; + var ap = Ember.ArrayProxy.create({ + content: Ember.A(pets), + objectAtContent: function(idx) { + return this.get('content').objectAt(idx).toUpperCase(); + } + }); + + ap.get('firstObject'); // . 'DOG' + ``` + + @class ArrayProxy + @namespace Ember + @extends Ember.Object + @uses Ember.MutableArray + */ + var ArrayProxy = EmberObject.extend(MutableArray, { + + /** + The content array. Must be an object that implements `Ember.Array` and/or + `Ember.MutableArray.` + + @property content + @type Ember.Array + */ + content: null, + + /** + The array that the proxy pretends to be. In the default `ArrayProxy` + implementation, this and `content` are the same. Subclasses of `ArrayProxy` + can override this property to provide things like sorting and filtering. + + @property arrangedContent + */ + arrangedContent: alias('content'), + + /** + Should actually retrieve the object at the specified index from the + content. You can override this method in subclasses to transform the + content item to something new. + + This method will only be called if content is non-`null`. + + @method objectAtContent + @param {Number} idx The index to retrieve. + @return {Object} the value or undefined if none found + */ + objectAtContent: function(idx) { + return get(this, 'arrangedContent').objectAt(idx); + }, + + /** + Should actually replace the specified objects on the content array. + You can override this method in subclasses to transform the content item + into something new. + + This method will only be called if content is non-`null`. + + @method replaceContent + @param {Number} idx The starting index + @param {Number} amt The number of items to remove from the content. + @param {Array} objects Optional array of objects to insert or null if no + objects. + @return {void} + */ + replaceContent: function(idx, amt, objects) { + get(this, 'content').replace(idx, amt, objects); + }, + + /** + Invoked when the content property is about to change. Notifies observers that the + entire array content will change. + + @private + @method _contentWillChange + */ + _contentWillChange: beforeObserver('content', function() { + this._teardownContent(); + }), + + _teardownContent: function() { + var content = get(this, 'content'); + + if (content) { + content.removeArrayObserver(this, { + willChange: 'contentArrayWillChange', + didChange: 'contentArrayDidChange' + }); + } + }, + + /** + Override to implement content array `willChange` observer. + + @method contentArrayWillChange + + @param {Ember.Array} contentArray the content array + @param {Number} start starting index of the change + @param {Number} removeCount count of items removed + @param {Number} addCount count of items added + + */ + contentArrayWillChange: K, + /** + Override to implement content array `didChange` observer. + + @method contentArrayDidChange + + @param {Ember.Array} contentArray the content array + @param {Number} start starting index of the change + @param {Number} removeCount count of items removed + @param {Number} addCount count of items added + */ + contentArrayDidChange: K, + + /** + Invoked when the content property changes. Notifies observers that the + entire array content has changed. + + @private + @method _contentDidChange + */ + _contentDidChange: observer('content', function() { + var content = get(this, 'content'); + + Ember.assert("Can't set ArrayProxy's content to itself", content !== this); + + this._setupContent(); + }), + + _setupContent: function() { + var content = get(this, 'content'); + + if (content) { + Ember.assert(fmt('ArrayProxy expects an Array or ' + + 'Ember.ArrayProxy, but you passed %@', [typeof content]), + isArray(content) || content.isDestroyed); + + content.addArrayObserver(this, { + willChange: 'contentArrayWillChange', + didChange: 'contentArrayDidChange' + }); + } + }, + + _arrangedContentWillChange: beforeObserver('arrangedContent', function() { + var arrangedContent = get(this, 'arrangedContent'); + var len = arrangedContent ? get(arrangedContent, 'length') : 0; + + this.arrangedContentArrayWillChange(this, 0, len, undefined); + this.arrangedContentWillChange(this); + + this._teardownArrangedContent(arrangedContent); + }), + + _arrangedContentDidChange: observer('arrangedContent', function() { + var arrangedContent = get(this, 'arrangedContent'); + var len = arrangedContent ? get(arrangedContent, 'length') : 0; + + Ember.assert("Can't set ArrayProxy's content to itself", arrangedContent !== this); + + this._setupArrangedContent(); + + this.arrangedContentDidChange(this); + this.arrangedContentArrayDidChange(this, 0, undefined, len); + }), + + _setupArrangedContent: function() { + var arrangedContent = get(this, 'arrangedContent'); + + if (arrangedContent) { + Ember.assert(fmt('ArrayProxy expects an Array or ' + + 'Ember.ArrayProxy, but you passed %@', [typeof arrangedContent]), + isArray(arrangedContent) || arrangedContent.isDestroyed); + + arrangedContent.addArrayObserver(this, { + willChange: 'arrangedContentArrayWillChange', + didChange: 'arrangedContentArrayDidChange' + }); + } + }, + + _teardownArrangedContent: function() { + var arrangedContent = get(this, 'arrangedContent'); + + if (arrangedContent) { + arrangedContent.removeArrayObserver(this, { + willChange: 'arrangedContentArrayWillChange', + didChange: 'arrangedContentArrayDidChange' + }); + } + }, + + arrangedContentWillChange: K, + arrangedContentDidChange: K, + + objectAt: function(idx) { + return get(this, 'content') && this.objectAtContent(idx); + }, + + length: computed(function() { + var arrangedContent = get(this, 'arrangedContent'); + return arrangedContent ? get(arrangedContent, 'length') : 0; + // No dependencies since Enumerable notifies length of change + }), + + _replace: function(idx, amt, objects) { + var content = get(this, 'content'); + Ember.assert('The content property of '+ this.constructor + ' should be set before modifying it', content); + if (content) this.replaceContent(idx, amt, objects); + return this; + }, + + replace: function() { + if (get(this, 'arrangedContent') === get(this, 'content')) { + apply(this, this._replace, arguments); + } else { + throw new EmberError("Using replace on an arranged ArrayProxy is not allowed."); + } + }, + + _insertAt: function(idx, object) { + if (idx > get(this, 'content.length')) throw new EmberError(OUT_OF_RANGE_EXCEPTION); + this._replace(idx, 0, [object]); + return this; + }, + + insertAt: function(idx, object) { + if (get(this, 'arrangedContent') === get(this, 'content')) { + return this._insertAt(idx, object); + } else { + throw new EmberError("Using insertAt on an arranged ArrayProxy is not allowed."); + } + }, + + removeAt: function(start, len) { + if ('number' === typeof start) { + var content = get(this, 'content'); + var arrangedContent = get(this, 'arrangedContent'); + var indices = []; + var i; + + if ((start < 0) || (start >= get(this, 'length'))) { + throw new EmberError(OUT_OF_RANGE_EXCEPTION); + } + + if (len === undefined) len = 1; + + // Get a list of indices in original content to remove + for (i=start; i= 0) { + var baseValue = this[keyName]; + + if (baseValue) { + if ('function' === typeof baseValue.concat) { + value = baseValue.concat(value); + } else { + value = makeArray(baseValue).concat(value); + } + } else { + value = makeArray(value); + } + } + + if (desc) { + desc.set(this, keyName, value); + } else { + if (typeof this.setUnknownProperty === 'function' && !(keyName in this)) { + this.setUnknownProperty(keyName, value); + } else { + + if (hasPropertyAccessors) { + defineProperty(this, keyName, null, value); // setup mandatory setter + } else { + this[keyName] = value; + } + } + } + } + } + } + finishPartial(this, m); + var length = arguments.length; + var args = new Array(length); + for (var x = 0; x < length; x++) { + args[x] = arguments[x]; + } + apply(this, this.init, args); + m.proto = proto; + finishChains(this); + sendEvent(this, "init"); + }; + + Class.toString = Mixin.prototype.toString; + Class.willReopen = function() { + if (wasApplied) { + Class.PrototypeMixin = Mixin.create(Class.PrototypeMixin); + } + + wasApplied = false; + }; + Class._initMixins = function(args) { initMixins = args; }; + Class._initProperties = function(args) { initProperties = args; }; + + Class.proto = function() { + var superclass = Class.superclass; + if (superclass) { superclass.proto(); } + + if (!wasApplied) { + wasApplied = true; + Class.PrototypeMixin.applyPartial(Class.prototype); + rewatch(Class.prototype); + } + + return this.prototype; + }; + + return Class; + + } + + /** + @class CoreObject + @namespace Ember + */ + var CoreObject = makeCtor(); + CoreObject.toString = function() { return "Ember.CoreObject"; }; + CoreObject.PrototypeMixin = Mixin.create({ + reopen: function() { + var length = arguments.length; + var args = new Array(length); + for (var i = 0; i < length; i++) { + args[i] = arguments[i]; + } + applyMixin(this, args, true); + return this; + }, + + /** + An overridable method called when objects are instantiated. By default, + does nothing unless it is overridden during class definition. + + Example: + + ```javascript + App.Person = Ember.Object.extend({ + init: function() { + alert('Name is ' + this.get('name')); + } + }); + + var steve = App.Person.create({ + name: "Steve" + }); + + // alerts 'Name is Steve'. + ``` + + NOTE: If you do override `init` for a framework class like `Ember.View` or + `Ember.ArrayController`, be sure to call `this._super()` in your + `init` declaration! If you don't, Ember may not have an opportunity to + do important setup work, and you'll see strange behavior in your + application. + + @method init + */ + init: function() {}, + + /** + Defines the properties that will be concatenated from the superclass + (instead of overridden). + + By default, when you extend an Ember class a property defined in + the subclass overrides a property with the same name that is defined + in the superclass. However, there are some cases where it is preferable + to build up a property's value by combining the superclass' property + value with the subclass' value. An example of this in use within Ember + is the `classNames` property of `Ember.View`. + + Here is some sample code showing the difference between a concatenated + property and a normal one: + + ```javascript + App.BarView = Ember.View.extend({ + someNonConcatenatedProperty: ['bar'], + classNames: ['bar'] + }); + + App.FooBarView = App.BarView.extend({ + someNonConcatenatedProperty: ['foo'], + classNames: ['foo'] + }); + + var fooBarView = App.FooBarView.create(); + fooBarView.get('someNonConcatenatedProperty'); // ['foo'] + fooBarView.get('classNames'); // ['ember-view', 'bar', 'foo'] + ``` + + This behavior extends to object creation as well. Continuing the + above example: + + ```javascript + var view = App.FooBarView.create({ + someNonConcatenatedProperty: ['baz'], + classNames: ['baz'] + }) + view.get('someNonConcatenatedProperty'); // ['baz'] + view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz'] + ``` + Adding a single property that is not an array will just add it in the array: + + ```javascript + var view = App.FooBarView.create({ + classNames: 'baz' + }) + view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz'] + ``` + + Using the `concatenatedProperties` property, we can tell to Ember that mix + the content of the properties. + + In `Ember.View` the `classNameBindings` and `attributeBindings` properties + are also concatenated, in addition to `classNames`. + + This feature is available for you to use throughout the Ember object model, + although typical app developers are likely to use it infrequently. Since + it changes expectations about behavior of properties, you should properly + document its usage in each individual concatenated property (to not + mislead your users to think they can override the property in a subclass). + + @property concatenatedProperties + @type Array + @default null + */ + concatenatedProperties: null, + + /** + Destroyed object property flag. + + if this property is `true` the observers and bindings were already + removed by the effect of calling the `destroy()` method. + + @property isDestroyed + @default false + */ + isDestroyed: false, + + /** + Destruction scheduled flag. The `destroy()` method has been called. + + The object stays intact until the end of the run loop at which point + the `isDestroyed` flag is set. + + @property isDestroying + @default false + */ + isDestroying: false, + + /** + Destroys an object by setting the `isDestroyed` flag and removing its + metadata, which effectively destroys observers and bindings. + + If you try to set a property on a destroyed object, an exception will be + raised. + + Note that destruction is scheduled for the end of the run loop and does not + happen immediately. It will set an isDestroying flag immediately. + + @method destroy + @return {Ember.Object} receiver + */ + destroy: function() { + if (this.isDestroying) { return; } + this.isDestroying = true; + + schedule('actions', this, this.willDestroy); + schedule('destroy', this, this._scheduledDestroy); + return this; + }, + + /** + Override to implement teardown. + + @method willDestroy + */ + willDestroy: K, + + /** + Invoked by the run loop to actually destroy the object. This is + scheduled for execution by the `destroy` method. + + @private + @method _scheduledDestroy + */ + _scheduledDestroy: function() { + if (this.isDestroyed) { return; } + destroy(this); + this.isDestroyed = true; + }, + + bind: function(to, from) { + if (!(from instanceof Binding)) { from = Binding.from(from); } + from.to(to).connect(this); + return from; + }, + + /** + Returns a string representation which attempts to provide more information + than Javascript's `toString` typically does, in a generic way for all Ember + objects. + + ```javascript + App.Person = Em.Object.extend() + person = App.Person.create() + person.toString() //=> "" + ``` + + If the object's class is not defined on an Ember namespace, it will + indicate it is a subclass of the registered superclass: + + ```javascript + Student = App.Person.extend() + student = Student.create() + student.toString() //=> "<(subclass of App.Person):ember1025>" + ``` + + If the method `toStringExtension` is defined, its return value will be + included in the output. + + ```javascript + App.Teacher = App.Person.extend({ + toStringExtension: function() { + return this.get('fullName'); + } + }); + teacher = App.Teacher.create() + teacher.toString(); //=> "" + ``` + + @method toString + @return {String} string representation + */ + toString: function toString() { + var hasToStringExtension = typeof this.toStringExtension === 'function'; + var extension = hasToStringExtension ? ":" + this.toStringExtension() : ''; + var ret = '<'+this.constructor.toString()+':'+guidFor(this)+extension+'>'; + + this.toString = makeToString(ret); + return ret; + } + }); + + CoreObject.PrototypeMixin.ownerConstructor = CoreObject; + + function makeToString(ret) { + return function() { return ret; }; + } + + if (Ember.config.overridePrototypeMixin) { + Ember.config.overridePrototypeMixin(CoreObject.PrototypeMixin); + } + + CoreObject.__super__ = null; + + var ClassMixin = Mixin.create({ + + ClassMixin: required(), + + PrototypeMixin: required(), + + isClass: true, + + isMethod: false, + + /** + Creates a new subclass. + + ```javascript + App.Person = Ember.Object.extend({ + say: function(thing) { + alert(thing); + } + }); + ``` + + This defines a new subclass of Ember.Object: `App.Person`. It contains one method: `say()`. + + You can also create a subclass from any existing class by calling its `extend()` method. For example, you might want to create a subclass of Ember's built-in `Ember.View` class: + + ```javascript + App.PersonView = Ember.View.extend({ + tagName: 'li', + classNameBindings: ['isAdministrator'] + }); + ``` + + When defining a subclass, you can override methods but still access the implementation of your parent class by calling the special `_super()` method: + + ```javascript + App.Person = Ember.Object.extend({ + say: function(thing) { + var name = this.get('name'); + alert(name + ' says: ' + thing); + } + }); + + App.Soldier = App.Person.extend({ + say: function(thing) { + this._super(thing + ", sir!"); + }, + march: function(numberOfHours) { + alert(this.get('name') + ' marches for ' + numberOfHours + ' hours.') + } + }); + + var yehuda = App.Soldier.create({ + name: "Yehuda Katz" + }); + + yehuda.say("Yes"); // alerts "Yehuda Katz says: Yes, sir!" + ``` + + The `create()` on line #17 creates an *instance* of the `App.Soldier` class. The `extend()` on line #8 creates a *subclass* of `App.Person`. Any instance of the `App.Person` class will *not* have the `march()` method. + + You can also pass `Mixin` classes to add additional properties to the subclass. + + ```javascript + App.Person = Ember.Object.extend({ + say: function(thing) { + alert(this.get('name') + ' says: ' + thing); + } + }); + + App.SingingMixin = Mixin.create({ + sing: function(thing){ + alert(this.get('name') + ' sings: la la la ' + thing); + } + }); + + App.BroadwayStar = App.Person.extend(App.SingingMixin, { + dance: function() { + alert(this.get('name') + ' dances: tap tap tap tap '); + } + }); + ``` + + The `App.BroadwayStar` class contains three methods: `say()`, `sing()`, and `dance()`. + + @method extend + @static + + @param {Mixin} [mixins]* One or more Mixin classes + @param {Object} [arguments]* Object containing values to use within the new class + */ + extend: function extend() { + var Class = makeCtor(); + var proto; + Class.ClassMixin = Mixin.create(this.ClassMixin); + Class.PrototypeMixin = Mixin.create(this.PrototypeMixin); + + Class.ClassMixin.ownerConstructor = Class; + Class.PrototypeMixin.ownerConstructor = Class; + + reopen.apply(Class.PrototypeMixin, arguments); + + Class.superclass = this; + Class.__super__ = this.prototype; + + proto = Class.prototype = o_create(this.prototype); + proto.constructor = Class; + generateGuid(proto); + meta(proto).proto = proto; // this will disable observers on prototype + + Class.ClassMixin.apply(Class); + return Class; + }, + + /** + Equivalent to doing `extend(arguments).create()`. + If possible use the normal `create` method instead. + + @method createWithMixins + @static + @param [arguments]* + */ + createWithMixins: function() { + var C = this; + var l= arguments.length; + if (l > 0) { + var args = new Array(l); + for (var i = 0; i < l; i++) { + args[i] = arguments[i]; + } + this._initMixins(args); + } + return new C(); + }, + + /** + Creates an instance of a class. Accepts either no arguments, or an object + containing values to initialize the newly instantiated object with. + + ```javascript + App.Person = Ember.Object.extend({ + helloWorld: function() { + alert("Hi, my name is " + this.get('name')); + } + }); + + var tom = App.Person.create({ + name: 'Tom Dale' + }); + + tom.helloWorld(); // alerts "Hi, my name is Tom Dale". + ``` + + `create` will call the `init` function if defined during + `Ember.AnyObject.extend` + + If no arguments are passed to `create`, it will not set values to the new + instance during initialization: + + ```javascript + var noName = App.Person.create(); + noName.helloWorld(); // alerts undefined + ``` + + NOTE: For performance reasons, you cannot declare methods or computed + properties during `create`. You should instead declare methods and computed + properties when using `extend` or use the `createWithMixins` shorthand. + + @method create + @static + @param [arguments]* + */ + create: function() { + var C = this; + var l = arguments.length; + if (l > 0) { + var args = new Array(l); + for (var i = 0; i < l; i++) { + args[i] = arguments[i]; + } + this._initProperties(args); + } + return new C(); + }, + + /** + Augments a constructor's prototype with additional + properties and functions: + + ```javascript + MyObject = Ember.Object.extend({ + name: 'an object' + }); + + o = MyObject.create(); + o.get('name'); // 'an object' + + MyObject.reopen({ + say: function(msg){ + console.log(msg); + } + }) + + o2 = MyObject.create(); + o2.say("hello"); // logs "hello" + + o.say("goodbye"); // logs "goodbye" + ``` + + To add functions and properties to the constructor itself, + see `reopenClass` + + @method reopen + */ + reopen: function() { + this.willReopen(); + + var l = arguments.length; + var args = new Array(l); + if (l > 0) { + for (var i = 0; i < l; i++) { + args[i] = arguments[i]; + } + } + + apply(this.PrototypeMixin, reopen, args); + return this; + }, + + /** + Augments a constructor's own properties and functions: + + ```javascript + MyObject = Ember.Object.extend({ + name: 'an object' + }); + + MyObject.reopenClass({ + canBuild: false + }); + + MyObject.canBuild; // false + o = MyObject.create(); + ``` + + In other words, this creates static properties and functions for the class. These are only available on the class + and not on any instance of that class. + + ```javascript + App.Person = Ember.Object.extend({ + name : "", + sayHello : function(){ + alert("Hello. My name is " + this.get('name')); + } + }); + + App.Person.reopenClass({ + species : "Homo sapiens", + createPerson: function(newPersonsName){ + return App.Person.create({ + name:newPersonsName + }); + } + }); + + var tom = App.Person.create({ + name : "Tom Dale" + }); + var yehuda = App.Person.createPerson("Yehuda Katz"); + + tom.sayHello(); // "Hello. My name is Tom Dale" + yehuda.sayHello(); // "Hello. My name is Yehuda Katz" + alert(App.Person.species); // "Homo sapiens" + ``` + + Note that `species` and `createPerson` are *not* valid on the `tom` and `yehuda` + variables. They are only valid on `App.Person`. + + To add functions and properties to instances of + a constructor by extending the constructor's prototype + see `reopen` + + @method reopenClass + */ + reopenClass: function() { + var l = arguments.length; + var args = new Array(l); + if (l > 0) { + for (var i = 0; i < l; i++) { + args[i] = arguments[i]; + } + } + + apply(this.ClassMixin, reopen, args); + applyMixin(this, arguments, false); + return this; + }, + + detect: function(obj) { + if ('function' !== typeof obj) { return false; } + while(obj) { + if (obj===this) { return true; } + obj = obj.superclass; + } + return false; + }, + + detectInstance: function(obj) { + return obj instanceof this; + }, + + /** + In some cases, you may want to annotate computed properties with additional + metadata about how they function or what values they operate on. For + example, computed property functions may close over variables that are then + no longer available for introspection. + + You can pass a hash of these values to a computed property like this: + + ```javascript + person: function() { + var personId = this.get('personId'); + return App.Person.create({ id: personId }); + }.property().meta({ type: App.Person }) + ``` + + Once you've done this, you can retrieve the values saved to the computed + property from your class like this: + + ```javascript + MyClass.metaForProperty('person'); + ``` + + This will return the original hash that was passed to `meta()`. + + @method metaForProperty + @param key {String} property name + */ + metaForProperty: function(key) { + var meta = this.proto()['__ember_meta__']; + var desc = meta && meta.descs[key]; + + Ember.assert("metaForProperty() could not find a computed property with key '"+key+"'.", !!desc && desc instanceof ComputedProperty); + return desc._meta || {}; + }, + + _computedProperties: Ember.computed(function() { + hasCachedComputedProperties = true; + var proto = this.proto(); + var descs = meta(proto).descs; + var property; + var properties = []; + + for (var name in descs) { + property = descs[name]; + + if (property instanceof ComputedProperty) { + properties.push({ + name: name, + meta: property._meta + }); + } + } + return properties; + }).readOnly(), + + /** + Iterate over each computed property for the class, passing its name + and any associated metadata (see `metaForProperty`) to the callback. + + @method eachComputedProperty + @param {Function} callback + @param {Object} binding + */ + eachComputedProperty: function(callback, binding) { + var property, name; + var empty = {}; + + var properties = get(this, '_computedProperties'); + + for (var i = 0, length = properties.length; i < length; i++) { + property = properties[i]; + name = property.name; + callback.call(binding || this, property.name, property.meta || empty); + } + } + }); + + ClassMixin.ownerConstructor = CoreObject; + + if (Ember.config.overrideClassMixin) { + Ember.config.overrideClassMixin(ClassMixin); + } + + CoreObject.ClassMixin = ClassMixin; + + ClassMixin.apply(CoreObject); + + CoreObject.reopen({ + didDefineProperty: function(proto, key, value) { + if (hasCachedComputedProperties === false) { return; } + if (value instanceof Ember.ComputedProperty) { + var cache = Ember.meta(this.constructor).cache; + + if (cache._computedProperties !== undefined) { + cache._computedProperties = undefined; + } + } + } + }); + + __exports__["default"] = CoreObject; + }); +enifed("ember-runtime/system/deferred", + ["ember-metal/core","ember-runtime/mixins/deferred","ember-metal/property_get","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var DeferredMixin = __dependency2__["default"]; + var get = __dependency3__.get; + var EmberObject = __dependency4__["default"]; + + var Deferred = EmberObject.extend(DeferredMixin, { + init: function() { + Ember.deprecate('Usage of Ember.Deferred is deprecated.'); + this._super(); + } + }); + + Deferred.reopenClass({ + promise: function(callback, binding) { + var deferred = Deferred.create(); + callback.call(binding, deferred); + return deferred; + } + }); + + __exports__["default"] = Deferred; + }); +enifed("ember-runtime/system/each_proxy", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/enumerable_utils","ember-metal/array","ember-runtime/mixins/array","ember-runtime/system/object","ember-metal/computed","ember-metal/observer","ember-metal/events","ember-metal/properties","ember-metal/property_events","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + // Ember.assert + + var get = __dependency2__.get; + var set = __dependency3__.set; + var guidFor = __dependency4__.guidFor; + var forEach = __dependency5__.forEach; + var indexOf = __dependency6__.indexOf; + var EmberArray = __dependency7__["default"]; + // ES6TODO: WAT? Circular dep? + var EmberObject = __dependency8__["default"]; + var computed = __dependency9__.computed; + var addObserver = __dependency10__.addObserver; + var addBeforeObserver = __dependency10__.addBeforeObserver; + var removeBeforeObserver = __dependency10__.removeBeforeObserver; + var removeObserver = __dependency10__.removeObserver; + var typeOf = __dependency4__.typeOf; + var watchedEvents = __dependency11__.watchedEvents; + var defineProperty = __dependency12__.defineProperty; + var beginPropertyChanges = __dependency13__.beginPropertyChanges; + var propertyDidChange = __dependency13__.propertyDidChange; + var propertyWillChange = __dependency13__.propertyWillChange; + var endPropertyChanges = __dependency13__.endPropertyChanges; + var changeProperties = __dependency13__.changeProperties; + + var EachArray = EmberObject.extend(EmberArray, { + + init: function(content, keyName, owner) { + this._super(); + this._keyName = keyName; + this._owner = owner; + this._content = content; + }, + + objectAt: function(idx) { + var item = this._content.objectAt(idx); + return item && get(item, this._keyName); + }, + + length: computed(function() { + var content = this._content; + return content ? get(content, 'length') : 0; + }) + + }); + + var IS_OBSERVER = /^.+:(before|change)$/; + + function addObserverForContentKey(content, keyName, proxy, idx, loc) { + var objects = proxy._objects; + var guid; + if (!objects) objects = proxy._objects = {}; + + while(--loc>=idx) { + var item = content.objectAt(loc); + if (item) { + Ember.assert('When using @each to observe the array ' + content + ', the array must return an object', typeOf(item) === 'instance' || typeOf(item) === 'object'); + addBeforeObserver(item, keyName, proxy, 'contentKeyWillChange'); + addObserver(item, keyName, proxy, 'contentKeyDidChange'); + + // keep track of the index each item was found at so we can map + // it back when the obj changes. + guid = guidFor(item); + if (!objects[guid]) objects[guid] = []; + objects[guid].push(loc); + } + } + } + + function removeObserverForContentKey(content, keyName, proxy, idx, loc) { + var objects = proxy._objects; + if (!objects) objects = proxy._objects = {}; + var indicies, guid; + + while(--loc>=idx) { + var item = content.objectAt(loc); + if (item) { + removeBeforeObserver(item, keyName, proxy, 'contentKeyWillChange'); + removeObserver(item, keyName, proxy, 'contentKeyDidChange'); + + guid = guidFor(item); + indicies = objects[guid]; + indicies[indexOf.call(indicies, loc)] = null; + } + } + } + + /** + This is the object instance returned when you get the `@each` property on an + array. It uses the unknownProperty handler to automatically create + EachArray instances for property names. + + @private + @class EachProxy + @namespace Ember + @extends Ember.Object + */ + var EachProxy = EmberObject.extend({ + + init: function(content) { + this._super(); + this._content = content; + content.addArrayObserver(this); + + // in case someone is already observing some keys make sure they are + // added + forEach(watchedEvents(this), function(eventName) { + this.didAddListener(eventName); + }, this); + }, + + /** + You can directly access mapped properties by simply requesting them. + The `unknownProperty` handler will generate an EachArray of each item. + + @method unknownProperty + @param keyName {String} + @param value {*} + */ + unknownProperty: function(keyName, value) { + var ret; + ret = new EachArray(this._content, keyName, this); + defineProperty(this, keyName, null, ret); + this.beginObservingContentKey(keyName); + return ret; + }, + + // .......................................................... + // ARRAY CHANGES + // Invokes whenever the content array itself changes. + + arrayWillChange: function(content, idx, removedCnt, addedCnt) { + var keys = this._keys; + var key, lim; + + lim = removedCnt>0 ? idx+removedCnt : -1; + beginPropertyChanges(this); + + for(key in keys) { + if (!keys.hasOwnProperty(key)) { continue; } + + if (lim>0) { removeObserverForContentKey(content, key, this, idx, lim); } + + propertyWillChange(this, key); + } + + propertyWillChange(this._content, '@each'); + endPropertyChanges(this); + }, + + arrayDidChange: function(content, idx, removedCnt, addedCnt) { + var keys = this._keys; + var lim; + + lim = addedCnt>0 ? idx+addedCnt : -1; + changeProperties(function() { + for(var key in keys) { + if (!keys.hasOwnProperty(key)) { continue; } + + if (lim>0) { addObserverForContentKey(content, key, this, idx, lim); } + + propertyDidChange(this, key); + } + + propertyDidChange(this._content, '@each'); + }, this); + }, + + // .......................................................... + // LISTEN FOR NEW OBSERVERS AND OTHER EVENT LISTENERS + // Start monitoring keys based on who is listening... + + didAddListener: function(eventName) { + if (IS_OBSERVER.test(eventName)) { + this.beginObservingContentKey(eventName.slice(0, -7)); + } + }, + + didRemoveListener: function(eventName) { + if (IS_OBSERVER.test(eventName)) { + this.stopObservingContentKey(eventName.slice(0, -7)); + } + }, + + // .......................................................... + // CONTENT KEY OBSERVING + // Actual watch keys on the source content. + + beginObservingContentKey: function(keyName) { + var keys = this._keys; + if (!keys) keys = this._keys = {}; + if (!keys[keyName]) { + keys[keyName] = 1; + var content = this._content; + var len = get(content, 'length'); + + addObserverForContentKey(content, keyName, this, 0, len); + } else { + keys[keyName]++; + } + }, + + stopObservingContentKey: function(keyName) { + var keys = this._keys; + if (keys && (keys[keyName]>0) && (--keys[keyName]<=0)) { + var content = this._content; + var len = get(content, 'length'); + + removeObserverForContentKey(content, keyName, this, 0, len); + } + }, + + contentKeyWillChange: function(obj, keyName) { + propertyWillChange(this, keyName); + }, + + contentKeyDidChange: function(obj, keyName) { + propertyDidChange(this, keyName); + } + }); + + __exports__.EachArray = EachArray; + __exports__.EachProxy = EachProxy; + }); +enifed("ember-runtime/system/lazy_load", + ["ember-metal/core","ember-metal/array","ember-runtime/system/native_array","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + /*globals CustomEvent */ + + var Ember = __dependency1__["default"]; + // Ember.ENV.EMBER_LOAD_HOOKS + var forEach = __dependency2__.forEach; + // make sure Ember.A is setup. + + /** + @module ember + @submodule ember-runtime + */ + + var loadHooks = Ember.ENV.EMBER_LOAD_HOOKS || {}; + var loaded = {}; + + /** + Detects when a specific package of Ember (e.g. 'Ember.Handlebars') + has fully loaded and is available for extension. + + The provided `callback` will be called with the `name` passed + resolved from a string into the object: + + ``` javascript + Ember.onLoad('Ember.Handlebars' function(hbars) { + hbars.registerHelper(...); + }); + ``` + + @method onLoad + @for Ember + @param name {String} name of hook + @param callback {Function} callback to be called + */ + function onLoad(name, callback) { + var object; + + loadHooks[name] = loadHooks[name] || Ember.A(); + loadHooks[name].pushObject(callback); + + if (object = loaded[name]) { + callback(object); + } + } + + __exports__.onLoad = onLoad;/** + Called when an Ember.js package (e.g Ember.Handlebars) has finished + loading. Triggers any callbacks registered for this event. + + @method runLoadHooks + @for Ember + @param name {String} name of hook + @param object {Object} object to pass to callbacks + */ + function runLoadHooks(name, object) { + loaded[name] = object; + + if (typeof window === 'object' && typeof window.dispatchEvent === 'function' && typeof CustomEvent === "function") { + var event = new CustomEvent(name, {detail: object, name: name}); + window.dispatchEvent(event); + } + + if (loadHooks[name]) { + forEach.call(loadHooks[name], function(callback) { + callback(object); + }); + } + } + + __exports__.runLoadHooks = runLoadHooks; + }); +enifed("ember-runtime/system/namespace", + ["ember-metal/core","ember-metal/property_get","ember-metal/array","ember-metal/utils","ember-metal/mixin","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + // Ember.lookup, Ember.BOOTED, Ember.deprecate, Ember.NAME_KEY, Ember.anyUnprocessedMixins + var Ember = __dependency1__["default"]; + var get = __dependency2__.get; + var indexOf = __dependency3__.indexOf; + var GUID_KEY = __dependency4__.GUID_KEY; + var guidFor = __dependency4__.guidFor; + var Mixin = __dependency5__.Mixin; + + var EmberObject = __dependency6__["default"]; + + /** + A Namespace is an object usually used to contain other objects or methods + such as an application or framework. Create a namespace anytime you want + to define one of these new containers. + + # Example Usage + + ```javascript + MyFramework = Ember.Namespace.create({ + VERSION: '1.0.0' + }); + ``` + + @class Namespace + @namespace Ember + @extends Ember.Object + */ + var Namespace = EmberObject.extend({ + isNamespace: true, + + init: function() { + Namespace.NAMESPACES.push(this); + Namespace.PROCESSED = false; + }, + + toString: function() { + var name = get(this, 'name') || get(this, 'modulePrefix'); + if (name) { return name; } + + findNamespaces(); + return this[NAME_KEY]; + }, + + nameClasses: function() { + processNamespace([this.toString()], this, {}); + }, + + destroy: function() { + var namespaces = Namespace.NAMESPACES; + var toString = this.toString(); + + if (toString) { + Ember.lookup[toString] = undefined; + delete Namespace.NAMESPACES_BY_ID[toString]; + } + namespaces.splice(indexOf.call(namespaces, this), 1); + this._super(); + } + }); + + Namespace.reopenClass({ + NAMESPACES: [Ember], + NAMESPACES_BY_ID: {}, + PROCESSED: false, + processAll: processAllNamespaces, + byName: function(name) { + if (!Ember.BOOTED) { + processAllNamespaces(); + } + + return NAMESPACES_BY_ID[name]; + } + }); + + var NAMESPACES_BY_ID = Namespace.NAMESPACES_BY_ID; + + var hasOwnProp = ({}).hasOwnProperty; + + function processNamespace(paths, root, seen) { + var idx = paths.length; + + NAMESPACES_BY_ID[paths.join('.')] = root; + + // Loop over all of the keys in the namespace, looking for classes + for(var key in root) { + if (!hasOwnProp.call(root, key)) { continue; } + var obj = root[key]; + + // If we are processing the `Ember` namespace, for example, the + // `paths` will start with `["Ember"]`. Every iteration through + // the loop will update the **second** element of this list with + // the key, so processing `Ember.View` will make the Array + // `['Ember', 'View']`. + paths[idx] = key; + + // If we have found an unprocessed class + if (obj && obj.toString === classToString) { + // Replace the class' `toString` with the dot-separated path + // and set its `NAME_KEY` + obj.toString = makeToString(paths.join('.')); + obj[NAME_KEY] = paths.join('.'); + + // Support nested namespaces + } else if (obj && obj.isNamespace) { + // Skip aliased namespaces + if (seen[guidFor(obj)]) { continue; } + seen[guidFor(obj)] = true; + + // Process the child namespace + processNamespace(paths, obj, seen); + } + } + + paths.length = idx; // cut out last item + } + + var STARTS_WITH_UPPERCASE = /^[A-Z]/; + + function tryIsNamespace(lookup, prop) { + try { + var obj = lookup[prop]; + return obj && obj.isNamespace && obj; + } catch (e) { + // continue + } + } + + function findNamespaces() { + var lookup = Ember.lookup; + var obj, isNamespace; + + if (Namespace.PROCESSED) { return; } + + for (var prop in lookup) { + // Only process entities that start with uppercase A-Z + if (!STARTS_WITH_UPPERCASE.test(prop)) { continue; } + + // Unfortunately, some versions of IE don't support window.hasOwnProperty + if (lookup.hasOwnProperty && !lookup.hasOwnProperty(prop)) { continue; } + + // At times we are not allowed to access certain properties for security reasons. + // There are also times where even if we can access them, we are not allowed to access their properties. + obj = tryIsNamespace(lookup, prop); + if (obj) { + obj[NAME_KEY] = prop; + } + } + } + + var NAME_KEY = Ember.NAME_KEY = GUID_KEY + '_name'; + + function superClassString(mixin) { + var superclass = mixin.superclass; + if (superclass) { + if (superclass[NAME_KEY]) { return superclass[NAME_KEY]; } + else { return superClassString(superclass); } + } else { + return; + } + } + + function classToString() { + if (!Ember.BOOTED && !this[NAME_KEY]) { + processAllNamespaces(); + } + + var ret; + + if (this[NAME_KEY]) { + ret = this[NAME_KEY]; + } else if (this._toString) { + ret = this._toString; + } else { + var str = superClassString(this); + if (str) { + ret = "(subclass of " + str + ")"; + } else { + ret = "(unknown mixin)"; + } + this.toString = makeToString(ret); + } + + return ret; + } + + function processAllNamespaces() { + var unprocessedNamespaces = !Namespace.PROCESSED; + var unprocessedMixins = Ember.anyUnprocessedMixins; + + if (unprocessedNamespaces) { + findNamespaces(); + Namespace.PROCESSED = true; + } + + if (unprocessedNamespaces || unprocessedMixins) { + var namespaces = Namespace.NAMESPACES; + var namespace; + + for (var i=0, l=namespaces.length; i 0) { + NativeArray = NativeArray.without.apply(NativeArray, ignore); + } + + /** + Creates an `Ember.NativeArray` from an Array like object. + Does not modify the original object. Ember.A is not needed if + `Ember.EXTEND_PROTOTYPES` is `true` (the default value). However, + it is recommended that you use Ember.A when creating addons for + ember or when you can not guarantee that `Ember.EXTEND_PROTOTYPES` + will be `true`. + + Example + + ```js + var Pagination = Ember.CollectionView.extend({ + tagName: 'ul', + classNames: ['pagination'], + + init: function() { + this._super(); + if (!this.get('content')) { + this.set('content', Ember.A()); + } + } + }); + ``` + + @method A + @for Ember + @return {Ember.NativeArray} + */ + var A = function(arr) { + if (arr === undefined) { arr = []; } + return EmberArray.detect(arr) ? arr : NativeArray.apply(arr); + }; + + /** + Activates the mixin on the Array.prototype if not already applied. Calling + this method more than once is safe. This will be called when ember is loaded + unless you have `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Array` + set to `false`. + + Example + + ```js + if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Array) { + Ember.NativeArray.activate(); + } + ``` + + @method activate + @for Ember.NativeArray + @static + @return {void} + */ + NativeArray.activate = function() { + NativeArray.apply(Array.prototype); + + A = function(arr) { return arr || []; }; + }; + + if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Array) { + NativeArray.activate(); + } + + Ember.A = A; // ES6TODO: Setting A onto the object returned by ember-metal/core to avoid circles + __exports__.A = A; + __exports__.NativeArray = NativeArray; + __exports__["default"] = NativeArray; + }); +enifed("ember-runtime/system/object", + ["ember-runtime/system/core_object","ember-runtime/mixins/observable","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var CoreObject = __dependency1__["default"]; + var Observable = __dependency2__["default"]; + + /** + `Ember.Object` is the main base class for all Ember objects. It is a subclass + of `Ember.CoreObject` with the `Ember.Observable` mixin applied. For details, + see the documentation for each of these. + + @class Object + @namespace Ember + @extends Ember.CoreObject + @uses Ember.Observable + */ + var EmberObject = CoreObject.extend(Observable); + EmberObject.toString = function() { + return "Ember.Object"; + }; + + __exports__["default"] = EmberObject; + }); +enifed("ember-runtime/system/object_proxy", + ["ember-runtime/system/object","ember-runtime/mixins/-proxy","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var EmberObject = __dependency1__["default"]; + var _ProxyMixin = __dependency2__["default"]; + + /** + `Ember.ObjectProxy` forwards all properties not defined by the proxy itself + to a proxied `content` object. + + ```javascript + object = Ember.Object.create({ + name: 'Foo' + }); + + proxy = Ember.ObjectProxy.create({ + content: object + }); + + // Access and change existing properties + proxy.get('name') // 'Foo' + proxy.set('name', 'Bar'); + object.get('name') // 'Bar' + + // Create new 'description' property on `object` + proxy.set('description', 'Foo is a whizboo baz'); + object.get('description') // 'Foo is a whizboo baz' + ``` + + While `content` is unset, setting a property to be delegated will throw an + Error. + + ```javascript + proxy = Ember.ObjectProxy.create({ + content: null, + flag: null + }); + proxy.set('flag', true); + proxy.get('flag'); // true + proxy.get('foo'); // undefined + proxy.set('foo', 'data'); // throws Error + ``` + + Delegated properties can be bound to and will change when content is updated. + + Computed properties on the proxy itself can depend on delegated properties. + + ```javascript + ProxyWithComputedProperty = Ember.ObjectProxy.extend({ + fullName: function () { + var firstName = this.get('firstName'), + lastName = this.get('lastName'); + if (firstName && lastName) { + return firstName + ' ' + lastName; + } + return firstName || lastName; + }.property('firstName', 'lastName') + }); + + proxy = ProxyWithComputedProperty.create(); + + proxy.get('fullName'); // undefined + proxy.set('content', { + firstName: 'Tom', lastName: 'Dale' + }); // triggers property change for fullName on proxy + + proxy.get('fullName'); // 'Tom Dale' + ``` + + @class ObjectProxy + @namespace Ember + @extends Ember.Object + @extends Ember._ProxyMixin + */ + + __exports__["default"] = EmberObject.extend(_ProxyMixin); + }); +enifed("ember-runtime/system/set", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/is_none","ember-runtime/system/string","ember-runtime/system/core_object","ember-runtime/mixins/mutable_enumerable","ember-runtime/mixins/enumerable","ember-runtime/mixins/copyable","ember-runtime/mixins/freezable","ember-metal/error","ember-metal/property_events","ember-metal/mixin","ember-metal/computed","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + var Ember = __dependency1__["default"]; + // Ember.isNone, Ember.A + + var get = __dependency2__.get; + var set = __dependency3__.set; + var guidFor = __dependency4__.guidFor; + var isNone = __dependency5__.isNone; + var fmt = __dependency6__.fmt; + var CoreObject = __dependency7__["default"]; + var MutableEnumerable = __dependency8__["default"]; + var Enumerable = __dependency9__["default"]; + var Copyable = __dependency10__["default"]; + var Freezable = __dependency11__.Freezable; + var FROZEN_ERROR = __dependency11__.FROZEN_ERROR; + var EmberError = __dependency12__["default"]; + var propertyWillChange = __dependency13__.propertyWillChange; + var propertyDidChange = __dependency13__.propertyDidChange; + var aliasMethod = __dependency14__.aliasMethod; + var computed = __dependency15__.computed; + + /** + An unordered collection of objects. + + A Set works a bit like an array except that its items are not ordered. You + can create a set to efficiently test for membership for an object. You can + also iterate through a set just like an array, even accessing objects by + index, however there is no guarantee as to their order. + + All Sets are observable via the Enumerable Observer API - which works + on any enumerable object including both Sets and Arrays. + + ## Creating a Set + + You can create a set like you would most objects using + `new Ember.Set()`. Most new sets you create will be empty, but you can + also initialize the set with some content by passing an array or other + enumerable of objects to the constructor. + + Finally, you can pass in an existing set and the set will be copied. You + can also create a copy of a set by calling `Ember.Set#copy()`. + + ```javascript + // creates a new empty set + var foundNames = new Ember.Set(); + + // creates a set with four names in it. + var names = new Ember.Set(["Charles", "Tom", "Juan", "Alex"]); // :P + + // creates a copy of the names set. + var namesCopy = new Ember.Set(names); + + // same as above. + var anotherNamesCopy = names.copy(); + ``` + + ## Adding/Removing Objects + + You generally add or remove objects from a set using `add()` or + `remove()`. You can add any type of object including primitives such as + numbers, strings, and booleans. + + Unlike arrays, objects can only exist one time in a set. If you call `add()` + on a set with the same object multiple times, the object will only be added + once. Likewise, calling `remove()` with the same object multiple times will + remove the object the first time and have no effect on future calls until + you add the object to the set again. + + NOTE: You cannot add/remove `null` or `undefined` to a set. Any attempt to do + so will be ignored. + + In addition to add/remove you can also call `push()`/`pop()`. Push behaves + just like `add()` but `pop()`, unlike `remove()` will pick an arbitrary + object, remove it and return it. This is a good way to use a set as a job + queue when you don't care which order the jobs are executed in. + + ## Testing for an Object + + To test for an object's presence in a set you simply call + `Ember.Set#contains()`. + + ## Observing changes + + When using `Ember.Set`, you can observe the `"[]"` property to be + alerted whenever the content changes. You can also add an enumerable + observer to the set to be notified of specific objects that are added and + removed from the set. See [Ember.Enumerable](/api/classes/Ember.Enumerable.html) + for more information on enumerables. + + This is often unhelpful. If you are filtering sets of objects, for instance, + it is very inefficient to re-filter all of the items each time the set + changes. It would be better if you could just adjust the filtered set based + on what was changed on the original set. The same issue applies to merging + sets, as well. + + ## Other Methods + + `Ember.Set` primary implements other mixin APIs. For a complete reference + on the methods you will use with `Ember.Set`, please consult these mixins. + The most useful ones will be `Ember.Enumerable` and + `Ember.MutableEnumerable` which implement most of the common iterator + methods you are used to on Array. + + Note that you can also use the `Ember.Copyable` and `Ember.Freezable` + APIs on `Ember.Set` as well. Once a set is frozen it can no longer be + modified. The benefit of this is that when you call `frozenCopy()` on it, + Ember will avoid making copies of the set. This allows you to write + code that can know with certainty when the underlying set data will or + will not be modified. + + @class Set + @namespace Ember + @extends Ember.CoreObject + @uses Ember.MutableEnumerable + @uses Ember.Copyable + @uses Ember.Freezable + @since Ember 0.9 + */ + __exports__["default"] = CoreObject.extend(MutableEnumerable, Copyable, Freezable, { + + // .......................................................... + // IMPLEMENT ENUMERABLE APIS + // + + /** + This property will change as the number of objects in the set changes. + + @property length + @type number + @default 0 + */ + length: 0, + + /** + Clears the set. This is useful if you want to reuse an existing set + without having to recreate it. + + ```javascript + var colors = new Ember.Set(["red", "green", "blue"]); + colors.length; // 3 + colors.clear(); + colors.length; // 0 + ``` + + @method clear + @return {Ember.Set} An empty Set + */ + clear: function() { + if (this.isFrozen) { throw new EmberError(FROZEN_ERROR); } + + var len = get(this, 'length'); + if (len === 0) { return this; } + + var guid; + + this.enumerableContentWillChange(len, 0); + propertyWillChange(this, 'firstObject'); + propertyWillChange(this, 'lastObject'); + + for (var i=0; i < len; i++) { + guid = guidFor(this[i]); + delete this[guid]; + delete this[i]; + } + + set(this, 'length', 0); + + propertyDidChange(this, 'firstObject'); + propertyDidChange(this, 'lastObject'); + this.enumerableContentDidChange(len, 0); + + return this; + }, + + /** + Returns true if the passed object is also an enumerable that contains the + same objects as the receiver. + + ```javascript + var colors = ["red", "green", "blue"], + same_colors = new Ember.Set(colors); + + same_colors.isEqual(colors); // true + same_colors.isEqual(["purple", "brown"]); // false + ``` + + @method isEqual + @param {Ember.Set} obj the other object. + @return {Boolean} + */ + isEqual: function(obj) { + // fail fast + if (!Enumerable.detect(obj)) return false; + + var loc = get(this, 'length'); + if (get(obj, 'length') !== loc) return false; + + while(--loc >= 0) { + if (!obj.contains(this[loc])) return false; + } + + return true; + }, + + /** + Adds an object to the set. Only non-`null` objects can be added to a set + and those can only be added once. If the object is already in the set or + the passed value is null this method will have no effect. + + This is an alias for `Ember.MutableEnumerable.addObject()`. + + ```javascript + var colors = new Ember.Set(); + colors.add("blue"); // ["blue"] + colors.add("blue"); // ["blue"] + colors.add("red"); // ["blue", "red"] + colors.add(null); // ["blue", "red"] + colors.add(undefined); // ["blue", "red"] + ``` + + @method add + @param {Object} obj The object to add. + @return {Ember.Set} The set itself. + */ + add: aliasMethod('addObject'), + + /** + Removes the object from the set if it is found. If you pass a `null` value + or an object that is already not in the set, this method will have no + effect. This is an alias for `Ember.MutableEnumerable.removeObject()`. + + ```javascript + var colors = new Ember.Set(["red", "green", "blue"]); + colors.remove("red"); // ["blue", "green"] + colors.remove("purple"); // ["blue", "green"] + colors.remove(null); // ["blue", "green"] + ``` + + @method remove + @param {Object} obj The object to remove + @return {Ember.Set} The set itself. + */ + remove: aliasMethod('removeObject'), + + /** + Removes the last element from the set and returns it, or `null` if it's empty. + + ```javascript + var colors = new Ember.Set(["green", "blue"]); + colors.pop(); // "blue" + colors.pop(); // "green" + colors.pop(); // null + ``` + + @method pop + @return {Object} The removed object from the set or null. + */ + pop: function() { + if (get(this, 'isFrozen')) throw new EmberError(FROZEN_ERROR); + var obj = this.length > 0 ? this[this.length-1] : null; + this.remove(obj); + return obj; + }, + + /** + Inserts the given object on to the end of the set. It returns + the set itself. + + This is an alias for `Ember.MutableEnumerable.addObject()`. + + ```javascript + var colors = new Ember.Set(); + colors.push("red"); // ["red"] + colors.push("green"); // ["red", "green"] + colors.push("blue"); // ["red", "green", "blue"] + ``` + + @method push + @return {Ember.Set} The set itself. + */ + push: aliasMethod('addObject'), + + /** + Removes the last element from the set and returns it, or `null` if it's empty. + + This is an alias for `Ember.Set.pop()`. + + ```javascript + var colors = new Ember.Set(["green", "blue"]); + colors.shift(); // "blue" + colors.shift(); // "green" + colors.shift(); // null + ``` + + @method shift + @return {Object} The removed object from the set or null. + */ + shift: aliasMethod('pop'), + + /** + Inserts the given object on to the end of the set. It returns + the set itself. + + This is an alias of `Ember.Set.push()` + + ```javascript + var colors = new Ember.Set(); + colors.unshift("red"); // ["red"] + colors.unshift("green"); // ["red", "green"] + colors.unshift("blue"); // ["red", "green", "blue"] + ``` + + @method unshift + @return {Ember.Set} The set itself. + */ + unshift: aliasMethod('push'), + + /** + Adds each object in the passed enumerable to the set. + + This is an alias of `Ember.MutableEnumerable.addObjects()` + + ```javascript + var colors = new Ember.Set(); + colors.addEach(["red", "green", "blue"]); // ["red", "green", "blue"] + ``` + + @method addEach + @param {Ember.Enumerable} objects the objects to add. + @return {Ember.Set} The set itself. + */ + addEach: aliasMethod('addObjects'), + + /** + Removes each object in the passed enumerable to the set. + + This is an alias of `Ember.MutableEnumerable.removeObjects()` + + ```javascript + var colors = new Ember.Set(["red", "green", "blue"]); + colors.removeEach(["red", "blue"]); // ["green"] + ``` + + @method removeEach + @param {Ember.Enumerable} objects the objects to remove. + @return {Ember.Set} The set itself. + */ + removeEach: aliasMethod('removeObjects'), + + // .......................................................... + // PRIVATE ENUMERABLE SUPPORT + // + + init: function(items) { + Ember.deprecate('Ember.Set is deprecated and will be removed in a future release.'); + this._super(); + if (items) this.addObjects(items); + }, + + // implement Ember.Enumerable + nextObject: function(idx) { + return this[idx]; + }, + + // more optimized version + firstObject: computed(function() { + return this.length > 0 ? this[0] : undefined; + }), + + // more optimized version + lastObject: computed(function() { + return this.length > 0 ? this[this.length-1] : undefined; + }), + + // implements Ember.MutableEnumerable + addObject: function(obj) { + if (get(this, 'isFrozen')) throw new EmberError(FROZEN_ERROR); + if (isNone(obj)) return this; // nothing to do + + var guid = guidFor(obj); + var idx = this[guid]; + var len = get(this, 'length'); + var added; + + if (idx>=0 && idx=0 && idx=0; + }, + + copy: function() { + var C = this.constructor, ret = new C(), loc = get(this, 'length'); + set(ret, 'length', loc); + while(--loc>=0) { + ret[loc] = this[loc]; + ret[guidFor(this[loc])] = loc; + } + return ret; + }, + + toString: function() { + var len = this.length, idx, array = []; + for(idx = 0; idx < len; idx++) { + array[idx] = this[idx]; + } + return fmt("Ember.Set<%@>", [array.join(',')]); + } + }); + }); +enifed("ember-runtime/system/string", + ["ember-metal/core","ember-metal/utils","ember-metal/cache","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + var Ember = __dependency1__["default"]; + // Ember.STRINGS, Ember.FEATURES + var isArray = __dependency2__.isArray; + var emberInspect = __dependency2__.inspect; + + var Cache = __dependency3__["default"]; + + var STRING_DASHERIZE_REGEXP = (/[ _]/g); + + var STRING_DASHERIZE_CACHE = new Cache(1000, function(key) { + return decamelize(key).replace(STRING_DASHERIZE_REGEXP, '-'); + }); + + var CAMELIZE_CACHE = new Cache(1000, function(key) { + return key.replace(STRING_CAMELIZE_REGEXP, function(match, separator, chr) { + return chr ? chr.toUpperCase() : ''; + }).replace(/^([A-Z])/, function(match, separator, chr) { + return match.toLowerCase(); + }); + }); + + var CLASSIFY_CACHE = new Cache(1000, function(str) { + var parts = str.split("."); + var out = []; + + for (var i=0, l=parts.length; i 2) { + cachedFormats = new Array(arguments.length - 1); + + for (var i = 1, l = arguments.length; i < l; i++) { + cachedFormats[i - 1] = arguments[i]; + } + } + + // first, replace any ORDERED replacements. + var idx = 0; // the current index for non-numerical replacements + return str.replace(/%@([0-9]+)?/g, function(s, argIndex) { + argIndex = (argIndex) ? parseInt(argIndex, 10) - 1 : idx++; + s = cachedFormats[argIndex]; + return (s === null) ? '(null)' : (s === undefined) ? '' : emberInspect(s); + }); + } + + function loc(str, formats) { + if (!isArray(formats) || arguments.length > 2) { + formats = Array.prototype.slice.call(arguments, 1); + } + + str = Ember.STRINGS[str] || str; + return fmt(str, formats); + } + + function w(str) { + return str.split(/\s+/); + } + + function decamelize(str) { + return DECAMELIZE_CACHE.get(str); + } + + function dasherize(str) { + return STRING_DASHERIZE_CACHE.get(str); + } + + function camelize(str) { + return CAMELIZE_CACHE.get(str); + } + + function classify(str) { + return CLASSIFY_CACHE.get(str); + } + + function underscore(str) { + return UNDERSCORE_CACHE.get(str); + } + + function capitalize(str) { + return CAPITALIZE_CACHE.get(str); + } + + /** + Defines the hash of localized strings for the current language. Used by + the `Ember.String.loc()` helper. To localize, add string values to this + hash. + + @property STRINGS + @for Ember + @type Hash + */ + Ember.STRINGS = {}; + + /** + Defines string helper methods including string formatting and localization. + Unless `Ember.EXTEND_PROTOTYPES.String` is `false` these methods will also be + added to the `String.prototype` as well. + + @class String + @namespace Ember + @static + */ + __exports__["default"] = { + /** + Apply formatting options to the string. This will look for occurrences + of "%@" in your string and substitute them with the arguments you pass into + this method. If you want to control the specific order of replacement, + you can add a number after the key as well to indicate which argument + you want to insert. + + Ordered insertions are most useful when building loc strings where values + you need to insert may appear in different orders. + + ```javascript + "Hello %@ %@".fmt('John', 'Doe'); // "Hello John Doe" + "Hello %@2, %@1".fmt('John', 'Doe'); // "Hello Doe, John" + ``` + + @method fmt + @param {String} str The string to format + @param {Array} formats An array of parameters to interpolate into string. + @return {String} formatted string + */ + fmt: fmt, + + /** + Formats the passed string, but first looks up the string in the localized + strings hash. This is a convenient way to localize text. See + `Ember.String.fmt()` for more information on formatting. + + Note that it is traditional but not required to prefix localized string + keys with an underscore or other character so you can easily identify + localized strings. + + ```javascript + Ember.STRINGS = { + '_Hello World': 'Bonjour le monde', + '_Hello %@ %@': 'Bonjour %@ %@' + }; + + Ember.String.loc("_Hello World"); // 'Bonjour le monde'; + Ember.String.loc("_Hello %@ %@", ["John", "Smith"]); // "Bonjour John Smith"; + ``` + + @method loc + @param {String} str The string to format + @param {Array} formats Optional array of parameters to interpolate into string. + @return {String} formatted string + */ + loc: loc, + + /** + Splits a string into separate units separated by spaces, eliminating any + empty strings in the process. This is a convenience method for split that + is mostly useful when applied to the `String.prototype`. + + ```javascript + Ember.String.w("alpha beta gamma").forEach(function(key) { + console.log(key); + }); + + // > alpha + // > beta + // > gamma + ``` + + @method w + @param {String} str The string to split + @return {Array} array containing the split strings + */ + w: w, + + /** + Converts a camelized string into all lower case separated by underscores. + + ```javascript + 'innerHTML'.decamelize(); // 'inner_html' + 'action_name'.decamelize(); // 'action_name' + 'css-class-name'.decamelize(); // 'css-class-name' + 'my favorite items'.decamelize(); // 'my favorite items' + ``` + + @method decamelize + @param {String} str The string to decamelize. + @return {String} the decamelized string. + */ + decamelize: decamelize, + + /** + Replaces underscores, spaces, or camelCase with dashes. + + ```javascript + 'innerHTML'.dasherize(); // 'inner-html' + 'action_name'.dasherize(); // 'action-name' + 'css-class-name'.dasherize(); // 'css-class-name' + 'my favorite items'.dasherize(); // 'my-favorite-items' + ``` + + @method dasherize + @param {String} str The string to dasherize. + @return {String} the dasherized string. + */ + dasherize: dasherize, + + /** + Returns the lowerCamelCase form of a string. + + ```javascript + 'innerHTML'.camelize(); // 'innerHTML' + 'action_name'.camelize(); // 'actionName' + 'css-class-name'.camelize(); // 'cssClassName' + 'my favorite items'.camelize(); // 'myFavoriteItems' + 'My Favorite Items'.camelize(); // 'myFavoriteItems' + ``` + + @method camelize + @param {String} str The string to camelize. + @return {String} the camelized string. + */ + camelize: camelize, + + /** + Returns the UpperCamelCase form of a string. + + ```javascript + 'innerHTML'.classify(); // 'InnerHTML' + 'action_name'.classify(); // 'ActionName' + 'css-class-name'.classify(); // 'CssClassName' + 'my favorite items'.classify(); // 'MyFavoriteItems' + ``` + + @method classify + @param {String} str the string to classify + @return {String} the classified string + */ + classify: classify, + + /** + More general than decamelize. Returns the lower\_case\_and\_underscored + form of a string. + + ```javascript + 'innerHTML'.underscore(); // 'inner_html' + 'action_name'.underscore(); // 'action_name' + 'css-class-name'.underscore(); // 'css_class_name' + 'my favorite items'.underscore(); // 'my_favorite_items' + ``` + + @method underscore + @param {String} str The string to underscore. + @return {String} the underscored string. + */ + underscore: underscore, + + /** + Returns the Capitalized form of a string + + ```javascript + 'innerHTML'.capitalize() // 'InnerHTML' + 'action_name'.capitalize() // 'Action_name' + 'css-class-name'.capitalize() // 'Css-class-name' + 'my favorite items'.capitalize() // 'My favorite items' + ``` + + @method capitalize + @param {String} str The string to capitalize. + @return {String} The capitalized string. + */ + capitalize: capitalize + }; + + __exports__.fmt = fmt; + __exports__.loc = loc; + __exports__.w = w; + __exports__.decamelize = decamelize; + __exports__.dasherize = dasherize; + __exports__.camelize = camelize; + __exports__.classify = classify; + __exports__.underscore = underscore; + __exports__.capitalize = capitalize; + }); +enifed("ember-runtime/system/subarray", + ["ember-metal/property_get","ember-metal/error","ember-metal/enumerable_utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var EmberError = __dependency2__["default"]; + var EnumerableUtils = __dependency3__["default"]; + + var RETAIN = 'r'; + var FILTER = 'f'; + + function Operation(type, count) { + this.type = type; + this.count = count; + } + + __exports__["default"] = SubArray; + + /** + An `Ember.SubArray` tracks an array in a way similar to, but more specialized + than, `Ember.TrackedArray`. It is useful for keeping track of the indexes of + items within a filtered array. + + @class SubArray + @namespace Ember + */ + function SubArray (length) { + if (arguments.length < 1) { length = 0; } + + if (length > 0) { + this._operations = [new Operation(RETAIN, length)]; + } else { + this._operations = []; + } + } + + + SubArray.prototype = { + /** + Track that an item was added to the tracked array. + + @method addItem + + @param {Number} index The index of the item in the tracked array. + @param {Boolean} match `true` iff the item is included in the subarray. + + @return {number} The index of the item in the subarray. + */ + addItem: function(index, match) { + var returnValue = -1; + var itemType = match ? RETAIN : FILTER; + var self = this; + + this._findOperation(index, function(operation, operationIndex, rangeStart, rangeEnd, seenInSubArray) { + var newOperation, splitOperation; + + if (itemType === operation.type) { + ++operation.count; + } else if (index === rangeStart) { + // insert to the left of `operation` + self._operations.splice(operationIndex, 0, new Operation(itemType, 1)); + } else { + newOperation = new Operation(itemType, 1); + splitOperation = new Operation(operation.type, rangeEnd - index + 1); + operation.count = index - rangeStart; + + self._operations.splice(operationIndex + 1, 0, newOperation, splitOperation); + } + + if (match) { + if (operation.type === RETAIN) { + returnValue = seenInSubArray + (index - rangeStart); + } else { + returnValue = seenInSubArray; + } + } + + self._composeAt(operationIndex); + }, function(seenInSubArray) { + self._operations.push(new Operation(itemType, 1)); + + if (match) { + returnValue = seenInSubArray; + } + + self._composeAt(self._operations.length-1); + }); + + return returnValue; + }, + + /** + Track that an item was removed from the tracked array. + + @method removeItem + + @param {Number} index The index of the item in the tracked array. + + @return {number} The index of the item in the subarray, or `-1` if the item + was not in the subarray. + */ + removeItem: function(index) { + var returnValue = -1; + var self = this; + + this._findOperation(index, function (operation, operationIndex, rangeStart, rangeEnd, seenInSubArray) { + if (operation.type === RETAIN) { + returnValue = seenInSubArray + (index - rangeStart); + } + + if (operation.count > 1) { + --operation.count; + } else { + self._operations.splice(operationIndex, 1); + self._composeAt(operationIndex); + } + }, function() { + throw new EmberError("Can't remove an item that has never been added."); + }); + + return returnValue; + }, + + + _findOperation: function (index, foundCallback, notFoundCallback) { + var seenInSubArray = 0; + var operationIndex, len, operation, rangeStart, rangeEnd; + + // OPTIMIZE: change to balanced tree + // find leftmost operation to the right of `index` + for (operationIndex = rangeStart = 0, len = this._operations.length; operationIndex < len; rangeStart = rangeEnd + 1, ++operationIndex) { + operation = this._operations[operationIndex]; + rangeEnd = rangeStart + operation.count - 1; + + if (index >= rangeStart && index <= rangeEnd) { + foundCallback(operation, operationIndex, rangeStart, rangeEnd, seenInSubArray); + return; + } else if (operation.type === RETAIN) { + seenInSubArray += operation.count; + } + } + + notFoundCallback(seenInSubArray); + }, + + _composeAt: function(index) { + var op = this._operations[index]; + var otherOp; + + if (!op) { + // Composing out of bounds is a no-op, as when removing the last operation + // in the list. + return; + } + + if (index > 0) { + otherOp = this._operations[index-1]; + if (otherOp.type === op.type) { + op.count += otherOp.count; + this._operations.splice(index-1, 1); + --index; + } + } + + if (index < this._operations.length-1) { + otherOp = this._operations[index+1]; + if (otherOp.type === op.type) { + op.count += otherOp.count; + this._operations.splice(index+1, 1); + } + } + }, + + toString: function () { + var str = ""; + EnumerableUtils.forEach(this._operations, function (operation) { + str += " " + operation.type + ":" + operation.count; + }); + return str.substring(1); + } + }; + }); +enifed("ember-runtime/system/tracked_array", + ["ember-metal/property_get","ember-metal/enumerable_utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var forEach = __dependency2__.forEach; + + var RETAIN = 'r'; + var INSERT = 'i'; + var DELETE = 'd'; + + __exports__["default"] = TrackedArray; + + /** + An `Ember.TrackedArray` tracks array operations. It's useful when you want to + lazily compute the indexes of items in an array after they've been shifted by + subsequent operations. + + @class TrackedArray + @namespace Ember + @param {Array} [items=[]] The array to be tracked. This is used just to get + the initial items for the starting state of retain:n. + */ + function TrackedArray(items) { + if (arguments.length < 1) { items = []; } + + var length = get(items, 'length'); + + if (length) { + this._operations = [new ArrayOperation(RETAIN, length, items)]; + } else { + this._operations = []; + } + } + + TrackedArray.RETAIN = RETAIN; + TrackedArray.INSERT = INSERT; + TrackedArray.DELETE = DELETE; + + TrackedArray.prototype = { + + /** + Track that `newItems` were added to the tracked array at `index`. + + @method addItems + @param index + @param newItems + */ + addItems: function (index, newItems) { + var count = get(newItems, 'length'); + if (count < 1) { return; } + + var match = this._findArrayOperation(index); + var arrayOperation = match.operation; + var arrayOperationIndex = match.index; + var arrayOperationRangeStart = match.rangeStart; + var composeIndex, splitIndex, splitItems, splitArrayOperation, newArrayOperation; + + newArrayOperation = new ArrayOperation(INSERT, count, newItems); + + if (arrayOperation) { + if (!match.split) { + // insert left of arrayOperation + this._operations.splice(arrayOperationIndex, 0, newArrayOperation); + composeIndex = arrayOperationIndex; + } else { + this._split(arrayOperationIndex, index - arrayOperationRangeStart, newArrayOperation); + composeIndex = arrayOperationIndex + 1; + } + } else { + // insert at end + this._operations.push(newArrayOperation); + composeIndex = arrayOperationIndex; + } + + this._composeInsert(composeIndex); + }, + + /** + Track that `count` items were removed at `index`. + + @method removeItems + @param index + @param count + */ + removeItems: function (index, count) { + if (count < 1) { return; } + + var match = this._findArrayOperation(index); + var arrayOperation = match.operation; + var arrayOperationIndex = match.index; + var arrayOperationRangeStart = match.rangeStart; + var newArrayOperation, composeIndex; + + newArrayOperation = new ArrayOperation(DELETE, count); + if (!match.split) { + // insert left of arrayOperation + this._operations.splice(arrayOperationIndex, 0, newArrayOperation); + composeIndex = arrayOperationIndex; + } else { + this._split(arrayOperationIndex, index - arrayOperationRangeStart, newArrayOperation); + composeIndex = arrayOperationIndex + 1; + } + + return this._composeDelete(composeIndex); + }, + + /** + Apply all operations, reducing them to retain:n, for `n`, the number of + items in the array. + + `callback` will be called for each operation and will be passed the following arguments: + + * {array} items The items for the given operation + * {number} offset The computed offset of the items, ie the index in the + array of the first item for this operation. + * {string} operation The type of the operation. One of + `Ember.TrackedArray.{RETAIN, DELETE, INSERT}` + + @method apply + @param {Function} callback + */ + apply: function (callback) { + var items = []; + var offset = 0; + + forEach(this._operations, function (arrayOperation, operationIndex) { + callback(arrayOperation.items, offset, arrayOperation.type, operationIndex); + + if (arrayOperation.type !== DELETE) { + offset += arrayOperation.count; + items = items.concat(arrayOperation.items); + } + }); + + this._operations = [new ArrayOperation(RETAIN, items.length, items)]; + }, + + /** + Return an `ArrayOperationMatch` for the operation that contains the item at `index`. + + @method _findArrayOperation + + @param {Number} index the index of the item whose operation information + should be returned. + @private + */ + _findArrayOperation: function (index) { + var split = false; + var arrayOperationIndex, arrayOperation, + arrayOperationRangeStart, arrayOperationRangeEnd, + len; + + // OPTIMIZE: we could search these faster if we kept a balanced tree. + // find leftmost arrayOperation to the right of `index` + for (arrayOperationIndex = arrayOperationRangeStart = 0, len = this._operations.length; arrayOperationIndex < len; ++arrayOperationIndex) { + arrayOperation = this._operations[arrayOperationIndex]; + + if (arrayOperation.type === DELETE) { continue; } + + arrayOperationRangeEnd = arrayOperationRangeStart + arrayOperation.count - 1; + + if (index === arrayOperationRangeStart) { + break; + } else if (index > arrayOperationRangeStart && index <= arrayOperationRangeEnd) { + split = true; + break; + } else { + arrayOperationRangeStart = arrayOperationRangeEnd + 1; + } + } + + return new ArrayOperationMatch(arrayOperation, arrayOperationIndex, split, arrayOperationRangeStart); + }, + + _split: function (arrayOperationIndex, splitIndex, newArrayOperation) { + var arrayOperation = this._operations[arrayOperationIndex]; + var splitItems = arrayOperation.items.slice(splitIndex); + var splitArrayOperation = new ArrayOperation(arrayOperation.type, splitItems.length, splitItems); + + // truncate LHS + arrayOperation.count = splitIndex; + arrayOperation.items = arrayOperation.items.slice(0, splitIndex); + + this._operations.splice(arrayOperationIndex + 1, 0, newArrayOperation, splitArrayOperation); + }, + + // see SubArray for a better implementation. + _composeInsert: function (index) { + var newArrayOperation = this._operations[index]; + var leftArrayOperation = this._operations[index-1]; // may be undefined + var rightArrayOperation = this._operations[index+1]; // may be undefined + var leftOp = leftArrayOperation && leftArrayOperation.type; + var rightOp = rightArrayOperation && rightArrayOperation.type; + + if (leftOp === INSERT) { + // merge left + leftArrayOperation.count += newArrayOperation.count; + leftArrayOperation.items = leftArrayOperation.items.concat(newArrayOperation.items); + + if (rightOp === INSERT) { + // also merge right (we have split an insert with an insert) + leftArrayOperation.count += rightArrayOperation.count; + leftArrayOperation.items = leftArrayOperation.items.concat(rightArrayOperation.items); + this._operations.splice(index, 2); + } else { + // only merge left + this._operations.splice(index, 1); + } + } else if (rightOp === INSERT) { + // merge right + newArrayOperation.count += rightArrayOperation.count; + newArrayOperation.items = newArrayOperation.items.concat(rightArrayOperation.items); + this._operations.splice(index + 1, 1); + } + }, + + _composeDelete: function (index) { + var arrayOperation = this._operations[index]; + var deletesToGo = arrayOperation.count; + var leftArrayOperation = this._operations[index-1]; // may be undefined + var leftOp = leftArrayOperation && leftArrayOperation.type; + var nextArrayOperation; + var nextOp; + var nextCount; + var removeNewAndNextOp = false; + var removedItems = []; + + if (leftOp === DELETE) { + arrayOperation = leftArrayOperation; + index -= 1; + } + + for (var i = index + 1; deletesToGo > 0; ++i) { + nextArrayOperation = this._operations[i]; + nextOp = nextArrayOperation.type; + nextCount = nextArrayOperation.count; + + if (nextOp === DELETE) { + arrayOperation.count += nextCount; + continue; + } + + if (nextCount > deletesToGo) { + // d:2 {r,i}:5 we reduce the retain or insert, but it stays + removedItems = removedItems.concat(nextArrayOperation.items.splice(0, deletesToGo)); + nextArrayOperation.count -= deletesToGo; + + // In the case where we truncate the last arrayOperation, we don't need to + // remove it; also the deletesToGo reduction is not the entirety of + // nextCount + i -= 1; + nextCount = deletesToGo; + + deletesToGo = 0; + } else { + if (nextCount === deletesToGo) { + // Handle edge case of d:2 i:2 in which case both operations go away + // during composition. + removeNewAndNextOp = true; + } + removedItems = removedItems.concat(nextArrayOperation.items); + deletesToGo -= nextCount; + } + + if (nextOp === INSERT) { + // d:2 i:3 will result in delete going away + arrayOperation.count -= nextCount; + } + } + + if (arrayOperation.count > 0) { + // compose our new delete with possibly several operations to the right of + // disparate types + this._operations.splice(index+1, i-1-index); + } else { + // The delete operation can go away; it has merely reduced some other + // operation, as in d:3 i:4; it may also have eliminated that operation, + // as in d:3 i:3. + this._operations.splice(index, removeNewAndNextOp ? 2 : 1); + } + + return removedItems; + }, + + toString: function () { + var str = ""; + forEach(this._operations, function (operation) { + str += " " + operation.type + ":" + operation.count; + }); + return str.substring(1); + } + }; + + /** + Internal data structure to represent an array operation. + + @method ArrayOperation + @private + @param {String} type The type of the operation. One of + `Ember.TrackedArray.{RETAIN, INSERT, DELETE}` + @param {Number} count The number of items in this operation. + @param {Array} items The items of the operation, if included. RETAIN and + INSERT include their items, DELETE does not. + */ + function ArrayOperation (operation, count, items) { + this.type = operation; // RETAIN | INSERT | DELETE + this.count = count; + this.items = items; + } + + /** + Internal data structure used to include information when looking up operations + by item index. + + @method ArrayOperationMatch + @private + @param {ArrayOperation} operation + @param {Number} index The index of `operation` in the array of operations. + @param {Boolean} split Whether or not the item index searched for would + require a split for a new operation type. + @param {Number} rangeStart The index of the first item in the operation, + with respect to the tracked array. The index of the last item can be computed + from `rangeStart` and `operation.count`. + */ + function ArrayOperationMatch(operation, index, split, rangeStart) { + this.operation = operation; + this.index = index; + this.split = split; + this.rangeStart = rangeStart; + } + }); +enifed("ember-testing", + ["ember-metal/core","ember-testing/initializers","ember-testing/support","ember-testing/setup_for_testing","ember-testing/test","ember-testing/adapters/adapter","ember-testing/adapters/qunit","ember-testing/helpers"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__) { + "use strict"; + var Ember = __dependency1__["default"]; + + // to setup initializer + // to handle various edge cases + + var setupForTesting = __dependency4__["default"]; + var Test = __dependency5__["default"]; + var Adapter = __dependency6__["default"]; + var QUnitAdapter = __dependency7__["default"]; + // adds helpers to helpers object in Test + + /** + Ember Testing + + @module ember + @submodule ember-testing + @requires ember-application + */ + + Ember.Test = Test; + Ember.Test.Adapter = Adapter; + Ember.Test.QUnitAdapter = QUnitAdapter; + Ember.setupForTesting = setupForTesting; + }); +enifed("ember-testing/adapters/adapter", + ["ember-metal/core","ember-metal/utils","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.K + var inspect = __dependency2__.inspect; + var EmberObject = __dependency3__["default"]; + + /** + @module ember + @submodule ember-testing + */ + + /** + The primary purpose of this class is to create hooks that can be implemented + by an adapter for various test frameworks. + + @class Adapter + @namespace Ember.Test + */ + var Adapter = EmberObject.extend({ + /** + This callback will be called whenever an async operation is about to start. + + Override this to call your framework's methods that handle async + operations. + + @public + @method asyncStart + */ + asyncStart: Ember.K, + + /** + This callback will be called whenever an async operation has completed. + + @public + @method asyncEnd + */ + asyncEnd: Ember.K, + + /** + Override this method with your testing framework's false assertion. + This function is called whenever an exception occurs causing the testing + promise to fail. + + QUnit example: + + ```javascript + exception: function(error) { + ok(false, error); + }; + ``` + + @public + @method exception + @param {String} error The exception to be raised. + */ + exception: function(error) { + throw error; + } + }); + + __exports__["default"] = Adapter; + }); +enifed("ember-testing/adapters/qunit", + ["ember-testing/adapters/adapter","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Adapter = __dependency1__["default"]; + var inspect = __dependency2__.inspect; + + /** + This class implements the methods defined by Ember.Test.Adapter for the + QUnit testing framework. + + @class QUnitAdapter + @namespace Ember.Test + @extends Ember.Test.Adapter + */ + __exports__["default"] = Adapter.extend({ + asyncStart: function() { + QUnit.stop(); + }, + asyncEnd: function() { + QUnit.start(); + }, + exception: function(error) { + ok(false, inspect(error)); + } + }); + }); +enifed("ember-testing/helpers", + ["ember-metal/property_get","ember-metal/error","ember-metal/run_loop","ember-views/system/jquery","ember-testing/test"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__) { + "use strict"; + var get = __dependency1__.get; + var EmberError = __dependency2__["default"]; + var run = __dependency3__["default"]; + var jQuery = __dependency4__["default"]; + var Test = __dependency5__["default"]; + + /** + * @module ember + * @submodule ember-testing + */ + + var helper = Test.registerHelper; + var asyncHelper = Test.registerAsyncHelper; + var countAsync = 0; + + function currentRouteName(app){ + var appController = app.__container__.lookup('controller:application'); + + return get(appController, 'currentRouteName'); + } + + function currentPath(app){ + var appController = app.__container__.lookup('controller:application'); + + return get(appController, 'currentPath'); + } + + function currentURL(app){ + var router = app.__container__.lookup('router:main'); + + return get(router, 'location').getURL(); + } + + function visit(app, url) { + var router = app.__container__.lookup('router:main'); + router.location.setURL(url); + + if (app._readinessDeferrals > 0) { + router['initialURL'] = url; + run(app, 'advanceReadiness'); + delete router['initialURL']; + } else { + run(app, app.handleURL, url); + } + + return app.testHelpers.wait(); + } + + function click(app, selector, context) { + var $el = app.testHelpers.findWithAssert(selector, context); + run($el, 'mousedown'); + + if ($el.is(':input')) { + var type = $el.prop('type'); + if (type !== 'checkbox' && type !== 'radio' && type !== 'hidden') { + run($el, function(){ + // Firefox does not trigger the `focusin` event if the window + // does not have focus. If the document doesn't have focus just + // use trigger('focusin') instead. + if (!document.hasFocus || document.hasFocus()) { + this.focus(); + } else { + this.trigger('focusin'); + } + }); + } + } + + run($el, 'mouseup'); + run($el, 'click'); + + return app.testHelpers.wait(); + } + + function triggerEvent(app, selector, contextOrType, typeOrOptions, possibleOptions){ + var arity = arguments.length; + var context, type, options; + + if (arity === 3) { + // context and options are optional, so this is + // app, selector, type + context = null; + type = contextOrType; + options = {}; + } else if (arity === 4) { + // context and options are optional, so this is + if (typeof typeOrOptions === "object") { // either + // app, selector, type, options + context = null; + type = contextOrType; + options = typeOrOptions; + } else { // or + // app, selector, context, type + context = contextOrType; + type = typeOrOptions; + options = {}; + } + } else { + context = contextOrType; + type = typeOrOptions; + options = possibleOptions; + } + + var $el = app.testHelpers.findWithAssert(selector, context); + + var event = jQuery.Event(type, options); + + run($el, 'trigger', event); + + return app.testHelpers.wait(); + } + + function keyEvent(app, selector, contextOrType, typeOrKeyCode, keyCode) { + var context, type; + + if (typeof keyCode === 'undefined') { + context = null; + keyCode = typeOrKeyCode; + type = contextOrType; + } else { + context = contextOrType; + type = typeOrKeyCode; + } + + return app.testHelpers.triggerEvent(selector, context, type, { keyCode: keyCode, which: keyCode }); + } + + function fillIn(app, selector, contextOrText, text) { + var $el, context; + if (typeof text === 'undefined') { + text = contextOrText; + } else { + context = contextOrText; + } + $el = app.testHelpers.findWithAssert(selector, context); + run(function() { + $el.val(text).change(); + }); + return app.testHelpers.wait(); + } + + function findWithAssert(app, selector, context) { + var $el = app.testHelpers.find(selector, context); + if ($el.length === 0) { + throw new EmberError("Element " + selector + " not found."); + } + return $el; + } + + function find(app, selector, context) { + var $el; + context = context || get(app, 'rootElement'); + $el = app.$(selector, context); + + return $el; + } + + function andThen(app, callback) { + return app.testHelpers.wait(callback(app)); + } + + function wait(app, value) { + return Test.promise(function(resolve) { + // If this is the first async promise, kick off the async test + if (++countAsync === 1) { + Test.adapter.asyncStart(); + } + + // Every 10ms, poll for the async thing to have finished + var watcher = setInterval(function() { + // 1. If the router is loading, keep polling + var routerIsLoading = !!app.__container__.lookup('router:main').router.activeTransition; + if (routerIsLoading) { return; } + + // 2. If there are pending Ajax requests, keep polling + if (Test.pendingAjaxRequests) { return; } + + // 3. If there are scheduled timers or we are inside of a run loop, keep polling + if (run.hasScheduledTimers() || run.currentRunLoop) { return; } + if (Test.waiters && Test.waiters.any(function(waiter) { + var context = waiter[0]; + var callback = waiter[1]; + return !callback.call(context); + })) { return; } + // Stop polling + clearInterval(watcher); + + // If this is the last async promise, end the async test + if (--countAsync === 0) { + Test.adapter.asyncEnd(); + } + + // Synchronously resolve the promise + run(null, resolve, value); + }, 10); + }); + + } + + + /** + * Loads a route, sets up any controllers, and renders any templates associated + * with the route as though a real user had triggered the route change while + * using your app. + * + * Example: + * + * ```javascript + * visit('posts/index').then(function() { + * // assert something + * }); + * ``` + * + * @method visit + * @param {String} url the name of the route + * @return {RSVP.Promise} + */ + asyncHelper('visit', visit); + + /** + * Clicks an element and triggers any actions triggered by the element's `click` + * event. + * + * Example: + * + * ```javascript + * click('.some-jQuery-selector').then(function() { + * // assert something + * }); + * ``` + * + * @method click + * @param {String} selector jQuery selector for finding element on the DOM + * @return {RSVP.Promise} + */ + asyncHelper('click', click); + + /** + * Simulates a key event, e.g. `keypress`, `keydown`, `keyup` with the desired keyCode + * + * Example: + * + * ```javascript + * keyEvent('.some-jQuery-selector', 'keypress', 13).then(function() { + * // assert something + * }); + * ``` + * + * @method keyEvent + * @param {String} selector jQuery selector for finding element on the DOM + * @param {String} type the type of key event, e.g. `keypress`, `keydown`, `keyup` + * @param {Number} keyCode the keyCode of the simulated key event + * @return {RSVP.Promise} + * @since 1.5.0 + */ + asyncHelper('keyEvent', keyEvent); + + /** + * Fills in an input element with some text. + * + * Example: + * + * ```javascript + * fillIn('#email', 'you@example.com').then(function() { + * // assert something + * }); + * ``` + * + * @method fillIn + * @param {String} selector jQuery selector finding an input element on the DOM + * to fill text with + * @param {String} text text to place inside the input element + * @return {RSVP.Promise} + */ + asyncHelper('fillIn', fillIn); + + /** + * Finds an element in the context of the app's container element. A simple alias + * for `app.$(selector)`. + * + * Example: + * + * ```javascript + * var $el = find('.my-selector'); + * ``` + * + * @method find + * @param {String} selector jQuery string selector for element lookup + * @return {Object} jQuery object representing the results of the query + */ + helper('find', find); + + /** + * Like `find`, but throws an error if the element selector returns no results. + * + * Example: + * + * ```javascript + * var $el = findWithAssert('.doesnt-exist'); // throws error + * ``` + * + * @method findWithAssert + * @param {String} selector jQuery selector string for finding an element within + * the DOM + * @return {Object} jQuery object representing the results of the query + * @throws {Error} throws error if jQuery object returned has a length of 0 + */ + helper('findWithAssert', findWithAssert); + + /** + Causes the run loop to process any pending events. This is used to ensure that + any async operations from other helpers (or your assertions) have been processed. + + This is most often used as the return value for the helper functions (see 'click', + 'fillIn','visit',etc). + + Example: + + ```javascript + Ember.Test.registerAsyncHelper('loginUser', function(app, username, password) { + visit('secured/path/here') + .fillIn('#username', username) + .fillIn('#password', username) + .click('.submit') + + return app.testHelpers.wait(); + }); + + @method wait + @param {Object} value The value to be returned. + @return {RSVP.Promise} + */ + asyncHelper('wait', wait); + asyncHelper('andThen', andThen); + + + /** + Returns the currently active route name. + + Example: + + ```javascript + function validateRouteName(){ + equal(currentRouteName(), 'some.path', "correct route was transitioned into."); + } + + visit('/some/path').then(validateRouteName) + ``` + + @method currentRouteName + @return {Object} The name of the currently active route. + @since 1.5.0 + */ + helper('currentRouteName', currentRouteName); + + /** + Returns the current path. + + Example: + + ```javascript + function validateURL(){ + equal(currentPath(), 'some.path.index', "correct path was transitioned into."); + } + + click('#some-link-id').then(validateURL); + ``` + + @method currentPath + @return {Object} The currently active path. + @since 1.5.0 + */ + helper('currentPath', currentPath); + + /** + Returns the current URL. + + Example: + + ```javascript + function validateURL(){ + equal(currentURL(), '/some/path', "correct URL was transitioned into."); + } + + click('#some-link-id').then(validateURL); + ``` + + @method currentURL + @return {Object} The currently active URL. + @since 1.5.0 + */ + helper('currentURL', currentURL); + + /** + Triggers the given DOM event on the element identified by the provided selector. + + Example: + + ```javascript + triggerEvent('#some-elem-id', 'blur'); + ``` + + This is actually used internally by the `keyEvent` helper like so: + + ```javascript + triggerEvent('#some-elem-id', 'keypress', { keyCode: 13 }); + ``` + + @method triggerEvent + @param {String} selector jQuery selector for finding element on the DOM + @param {String} [context] jQuery selector that will limit the selector + argument to find only within the context's children + @param {String} type The event type to be triggered. + @param {Object} [options] The options to be passed to jQuery.Event. + @return {RSVP.Promise} + @since 1.5.0 + */ + asyncHelper('triggerEvent', triggerEvent); + }); +enifed("ember-testing/initializers", + ["ember-runtime/system/lazy_load"], + function(__dependency1__) { + "use strict"; + var onLoad = __dependency1__.onLoad; + + var name = 'deferReadiness in `testing` mode'; + + onLoad('Ember.Application', function(Application) { + if (!Application.initializers[name]) { + Application.initializer({ + name: name, + + initialize: function(container, application){ + if (application.testing) { + application.deferReadiness(); + } + } + }); + } + }); + }); +enifed("ember-testing/setup_for_testing", + ["ember-metal/core","ember-testing/adapters/qunit","ember-views/system/jquery","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // import Test from "ember-testing/test"; // ES6TODO: fix when cycles are supported + var QUnitAdapter = __dependency2__["default"]; + var jQuery = __dependency3__["default"]; + + var Test, requests; + + function incrementAjaxPendingRequests(_, xhr){ + requests.push(xhr); + Test.pendingAjaxRequests = requests.length; + } + + function decrementAjaxPendingRequests(_, xhr){ + for (var i=0;i') + .css({ position: 'absolute', left: '-1000px', top: '-1000px' }) + .appendTo('body') + .on('click', handler) + .trigger('click') + .remove(); + } + + $(function() { + /* + Determine whether a checkbox checked using jQuery's "click" method will have + the correct value for its checked property. + + If we determine that the current jQuery version exhibits this behavior, + patch it to work correctly as in the commit for the actual fix: + https://github.com/jquery/jquery/commit/1fb2f92. + */ + testCheckboxClick(function() { + if (!this.checked && !$.event.special.click) { + $.event.special.click = { + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ($.nodeName( this, "input" ) && this.type === "checkbox" && this.click) { + this.click(); + return false; + } + } + }; + } + }); + + // Try again to verify that the patch took effect or blow up. + testCheckboxClick(function() { + Ember.warn("clicked checkboxes should be checked! the jQuery patch didn't work", this.checked); + }); + }); + }); +enifed("ember-testing/test", + ["ember-metal/core","ember-metal/run_loop","ember-metal/platform","ember-runtime/compare","ember-runtime/ext/rsvp","ember-testing/setup_for_testing","ember-application/system/application","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var emberRun = __dependency2__["default"]; + var create = __dependency3__.create; + var compare = __dependency4__["default"]; + var RSVP = __dependency5__["default"]; + var setupForTesting = __dependency6__["default"]; + var EmberApplication = __dependency7__["default"]; + + /** + @module ember + @submodule ember-testing + */ + var slice = [].slice; + var helpers = {}; + var injectHelpersCallbacks = []; + + /** + This is a container for an assortment of testing related functionality: + + * Choose your default test adapter (for your framework of choice). + * Register/Unregister additional test helpers. + * Setup callbacks to be fired when the test helpers are injected into + your application. + + @class Test + @namespace Ember + */ + var Test = { + /** + Hash containing all known test helpers. + + @property _helpers + @private + @since 1.7.0 + */ + _helpers: helpers, + + /** + `registerHelper` is used to register a test helper that will be injected + when `App.injectTestHelpers` is called. + + The helper method will always be called with the current Application as + the first parameter. + + For example: + + ```javascript + Ember.Test.registerHelper('boot', function(app) { + Ember.run(app, app.advanceReadiness); + }); + ``` + + This helper can later be called without arguments because it will be + called with `app` as the first parameter. + + ```javascript + App = Ember.Application.create(); + App.injectTestHelpers(); + boot(); + ``` + + @public + @method registerHelper + @param {String} name The name of the helper method to add. + @param {Function} helperMethod + @param options {Object} + */ + registerHelper: function(name, helperMethod) { + helpers[name] = { + method: helperMethod, + meta: { wait: false } + }; + }, + + /** + `registerAsyncHelper` is used to register an async test helper that will be injected + when `App.injectTestHelpers` is called. + + The helper method will always be called with the current Application as + the first parameter. + + For example: + + ```javascript + Ember.Test.registerAsyncHelper('boot', function(app) { + Ember.run(app, app.advanceReadiness); + }); + ``` + + The advantage of an async helper is that it will not run + until the last async helper has completed. All async helpers + after it will wait for it complete before running. + + + For example: + + ```javascript + Ember.Test.registerAsyncHelper('deletePost', function(app, postId) { + click('.delete-' + postId); + }); + + // ... in your test + visit('/post/2'); + deletePost(2); + visit('/post/3'); + deletePost(3); + ``` + + @public + @method registerAsyncHelper + @param {String} name The name of the helper method to add. + @param {Function} helperMethod + @since 1.2.0 + */ + registerAsyncHelper: function(name, helperMethod) { + helpers[name] = { + method: helperMethod, + meta: { wait: true } + }; + }, + + /** + Remove a previously added helper method. + + Example: + + ```javascript + Ember.Test.unregisterHelper('wait'); + ``` + + @public + @method unregisterHelper + @param {String} name The helper to remove. + */ + unregisterHelper: function(name) { + delete helpers[name]; + delete Test.Promise.prototype[name]; + }, + + /** + Used to register callbacks to be fired whenever `App.injectTestHelpers` + is called. + + The callback will receive the current application as an argument. + + Example: + + ```javascript + Ember.Test.onInjectHelpers(function() { + Ember.$(document).ajaxSend(function() { + Test.pendingAjaxRequests++; + }); + + Ember.$(document).ajaxComplete(function() { + Test.pendingAjaxRequests--; + }); + }); + ``` + + @public + @method onInjectHelpers + @param {Function} callback The function to be called. + */ + onInjectHelpers: function(callback) { + injectHelpersCallbacks.push(callback); + }, + + /** + This returns a thenable tailored for testing. It catches failed + `onSuccess` callbacks and invokes the `Ember.Test.adapter.exception` + callback in the last chained then. + + This method should be returned by async helpers such as `wait`. + + @public + @method promise + @param {Function} resolver The function used to resolve the promise. + */ + promise: function(resolver) { + return new Test.Promise(resolver); + }, + + /** + Used to allow ember-testing to communicate with a specific testing + framework. + + You can manually set it before calling `App.setupForTesting()`. + + Example: + + ```javascript + Ember.Test.adapter = MyCustomAdapter.create() + ``` + + If you do not set it, ember-testing will default to `Ember.Test.QUnitAdapter`. + + @public + @property adapter + @type {Class} The adapter to be used. + @default Ember.Test.QUnitAdapter + */ + adapter: null, + + /** + Replacement for `Ember.RSVP.resolve` + The only difference is this uses + an instance of `Ember.Test.Promise` + + @public + @method resolve + @param {Mixed} The value to resolve + @since 1.2.0 + */ + resolve: function(val) { + return Test.promise(function(resolve) { + return resolve(val); + }); + }, + + /** + This allows ember-testing to play nicely with other asynchronous + events, such as an application that is waiting for a CSS3 + transition or an IndexDB transaction. + + For example: + + ```javascript + Ember.Test.registerWaiter(function() { + return myPendingTransactions() == 0; + }); + ``` + The `context` argument allows you to optionally specify the `this` + with which your callback will be invoked. + + For example: + + ```javascript + Ember.Test.registerWaiter(MyDB, MyDB.hasPendingTransactions); + ``` + + @public + @method registerWaiter + @param {Object} context (optional) + @param {Function} callback + @since 1.2.0 + */ + registerWaiter: function(context, callback) { + if (arguments.length === 1) { + callback = context; + context = null; + } + if (!this.waiters) { + this.waiters = Ember.A(); + } + this.waiters.push([context, callback]); + }, + /** + `unregisterWaiter` is used to unregister a callback that was + registered with `registerWaiter`. + + @public + @method unregisterWaiter + @param {Object} context (optional) + @param {Function} callback + @since 1.2.0 + */ + unregisterWaiter: function(context, callback) { + var pair; + if (!this.waiters) { return; } + if (arguments.length === 1) { + callback = context; + context = null; + } + pair = [context, callback]; + this.waiters = Ember.A(this.waiters.filter(function(elt) { + return compare(elt, pair)!==0; + })); + } + }; + + function helper(app, name) { + var fn = helpers[name].method; + var meta = helpers[name].meta; + + return function() { + var args = slice.call(arguments); + var lastPromise = Test.lastPromise; + + args.unshift(app); + + // some helpers are not async and + // need to return a value immediately. + // example: `find` + if (!meta.wait) { + return fn.apply(app, args); + } + + if (!lastPromise) { + // It's the first async helper in current context + lastPromise = fn.apply(app, args); + } else { + // wait for last helper's promise to resolve + // and then execute + run(function() { + lastPromise = Test.resolve(lastPromise).then(function() { + return fn.apply(app, args); + }); + }); + } + + return lastPromise; + }; + } + + function run(fn) { + if (!emberRun.currentRunLoop) { + emberRun(fn); + } else { + fn(); + } + } + + EmberApplication.reopen({ + /** + This property contains the testing helpers for the current application. These + are created once you call `injectTestHelpers` on your `Ember.Application` + instance. The included helpers are also available on the `window` object by + default, but can be used from this object on the individual application also. + + @property testHelpers + @type {Object} + @default {} + */ + testHelpers: {}, + + /** + This property will contain the original methods that were registered + on the `helperContainer` before `injectTestHelpers` is called. + + When `removeTestHelpers` is called, these methods are restored to the + `helperContainer`. + + @property originalMethods + @type {Object} + @default {} + @private + @since 1.3.0 + */ + originalMethods: {}, + + + /** + This property indicates whether or not this application is currently in + testing mode. This is set when `setupForTesting` is called on the current + application. + + @property testing + @type {Boolean} + @default false + @since 1.3.0 + */ + testing: false, + + /** + This hook defers the readiness of the application, so that you can start + the app when your tests are ready to run. It also sets the router's + location to 'none', so that the window's location will not be modified + (preventing both accidental leaking of state between tests and interference + with your testing framework). + + Example: + + ``` + App.setupForTesting(); + ``` + + @method setupForTesting + */ + setupForTesting: function() { + setupForTesting(); + + this.testing = true; + + this.Router.reopen({ + location: 'none' + }); + }, + + /** + This will be used as the container to inject the test helpers into. By + default the helpers are injected into `window`. + + @property helperContainer + @type {Object} The object to be used for test helpers. + @default window + @since 1.2.0 + */ + helperContainer: window, + + /** + This injects the test helpers into the `helperContainer` object. If an object is provided + it will be used as the helperContainer. If `helperContainer` is not set it will default + to `window`. If a function of the same name has already been defined it will be cached + (so that it can be reset if the helper is removed with `unregisterHelper` or + `removeTestHelpers`). + + Any callbacks registered with `onInjectHelpers` will be called once the + helpers have been injected. + + Example: + ``` + App.injectTestHelpers(); + ``` + + @method injectTestHelpers + */ + injectTestHelpers: function(helperContainer) { + if (helperContainer) { this.helperContainer = helperContainer; } + + this.testHelpers = {}; + for (var name in helpers) { + this.originalMethods[name] = this.helperContainer[name]; + this.testHelpers[name] = this.helperContainer[name] = helper(this, name); + protoWrap(Test.Promise.prototype, name, helper(this, name), helpers[name].meta.wait); + } + + for(var i = 0, l = injectHelpersCallbacks.length; i < l; i++) { + injectHelpersCallbacks[i](this); + } + }, + + /** + This removes all helpers that have been registered, and resets and functions + that were overridden by the helpers. + + Example: + + ```javascript + App.removeTestHelpers(); + ``` + + @public + @method removeTestHelpers + */ + removeTestHelpers: function() { + for (var name in helpers) { + this.helperContainer[name] = this.originalMethods[name]; + delete this.testHelpers[name]; + delete this.originalMethods[name]; + } + } + }); + + // This method is no longer needed + // But still here for backwards compatibility + // of helper chaining + function protoWrap(proto, name, callback, isAsync) { + proto[name] = function() { + var args = arguments; + if (isAsync) { + return callback.apply(this, args); + } else { + return this.then(function() { + return callback.apply(this, args); + }); + } + }; + } + + Test.Promise = function() { + RSVP.Promise.apply(this, arguments); + Test.lastPromise = this; + }; + + Test.Promise.prototype = create(RSVP.Promise.prototype); + Test.Promise.prototype.constructor = Test.Promise; + + // Patch `then` to isolate async methods + // specifically `Ember.Test.lastPromise` + var originalThen = RSVP.Promise.prototype.then; + Test.Promise.prototype.then = function(onSuccess, onFailure) { + return originalThen.call(this, function(val) { + return isolate(onSuccess, val); + }, onFailure); + }; + + // This method isolates nested async methods + // so that they don't conflict with other last promises. + // + // 1. Set `Ember.Test.lastPromise` to null + // 2. Invoke method + // 3. Return the last promise created during method + // 4. Restore `Ember.Test.lastPromise` to original value + function isolate(fn, val) { + var value, lastPromise; + + // Reset lastPromise for nested helpers + Test.lastPromise = null; + + value = fn(val); + + lastPromise = Test.lastPromise; + + // If the method returned a promise + // return that promise. If not, + // return the last async helper's promise + if ((value && (value instanceof Test.Promise)) || !lastPromise) { + return value; + } else { + run(function() { + lastPromise = Test.resolve(lastPromise).then(function() { + return value; + }); + }); + return lastPromise; + } + } + + __exports__["default"] = Test; + }); +enifed("ember-views", + ["ember-runtime","ember-views/system/jquery","ember-views/system/utils","ember-views/system/render_buffer","ember-views/system/ext","ember-views/views/states","ember-views/views/core_view","ember-views/views/view","ember-views/views/container_view","ember-views/views/collection_view","ember-views/views/component","ember-views/system/event_dispatcher","ember-views/mixins/view_target_action_support","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __exports__) { + "use strict"; + /** + Ember Views + + @module ember + @submodule ember-views + @requires ember-runtime + @main ember-views + */ + + // BEGIN IMPORTS + var Ember = __dependency1__["default"]; + var jQuery = __dependency2__["default"]; + var isSimpleClick = __dependency3__.isSimpleClick; + var RenderBuffer = __dependency4__["default"]; + // for the side effect of extending Ember.run.queues + var cloneStates = __dependency6__.cloneStates; + var states = __dependency6__.states; + + var CoreView = __dependency7__["default"]; + var View = __dependency8__["default"]; + var ContainerView = __dependency9__["default"]; + var CollectionView = __dependency10__["default"]; + var Component = __dependency11__["default"]; + + var EventDispatcher = __dependency12__["default"]; + var ViewTargetActionSupport = __dependency13__["default"]; + // END IMPORTS + + /** + Alias for jQuery + + @method $ + @for Ember + */ + + // BEGIN EXPORTS + Ember.$ = jQuery; + + Ember.ViewTargetActionSupport = ViewTargetActionSupport; + Ember.RenderBuffer = RenderBuffer; + + var ViewUtils = Ember.ViewUtils = {}; + ViewUtils.isSimpleClick = isSimpleClick; + + Ember.CoreView = CoreView; + Ember.View = View; + Ember.View.states = states; + Ember.View.cloneStates = cloneStates; + + Ember.ContainerView = ContainerView; + Ember.CollectionView = CollectionView; + Ember.Component = Component; + Ember.EventDispatcher = EventDispatcher; + // END EXPORTS + + __exports__["default"] = Ember; + }); +enifed("ember-views/mixins/component_template_deprecation", + ["ember-metal/core","ember-metal/property_get","ember-metal/mixin","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.deprecate + var get = __dependency2__.get; + var Mixin = __dependency3__.Mixin; + + /** + The ComponentTemplateDeprecation mixin is used to provide a useful + deprecation warning when using either `template` or `templateName` with + a component. The `template` and `templateName` properties specified at + extend time are moved to `layout` and `layoutName` respectively. + + `Ember.ComponentTemplateDeprecation` is used internally by Ember in + `Ember.Component`. + + @class ComponentTemplateDeprecation + @namespace Ember + */ + __exports__["default"] = Mixin.create({ + /** + @private + + Moves `templateName` to `layoutName` and `template` to `layout` at extend + time if a layout is not also specified. + + Note that this currently modifies the mixin themselves, which is technically + dubious but is practically of little consequence. This may change in the + future. + + @method willMergeMixin + @since 1.4.0 + */ + willMergeMixin: function(props) { + // must call _super here to ensure that the ActionHandler + // mixin is setup properly (moves actions -> _actions) + // + // Calling super is only OK here since we KNOW that + // there is another Mixin loaded first. + this._super.apply(this, arguments); + + var deprecatedProperty, replacementProperty; + var layoutSpecified = (props.layoutName || props.layout || get(this, 'layoutName')); + + if (props.templateName && !layoutSpecified) { + deprecatedProperty = 'templateName'; + replacementProperty = 'layoutName'; + + props.layoutName = props.templateName; + delete props['templateName']; + } + + if (props.template && !layoutSpecified) { + deprecatedProperty = 'template'; + replacementProperty = 'layout'; + + props.layout = props.template; + delete props['template']; + } + + if (deprecatedProperty) { + Ember.deprecate('Do not specify ' + deprecatedProperty + ' on a Component, use ' + replacementProperty + ' instead.', false); + } + } + }); + }); +enifed("ember-views/mixins/view_target_action_support", + ["ember-metal/mixin","ember-runtime/mixins/target_action_support","ember-metal/computed","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Mixin = __dependency1__.Mixin; + var TargetActionSupport = __dependency2__["default"]; + + // ES6TODO: computed should have its own export path so you can do import {defaultTo} from computed + var computed = __dependency3__.computed; + var alias = computed.alias; + + /** + `Ember.ViewTargetActionSupport` is a mixin that can be included in a + view class to add a `triggerAction` method with semantics similar to + the Handlebars `{{action}}` helper. It provides intelligent defaults + for the action's target: the view's controller; and the context that is + sent with the action: the view's context. + + Note: In normal Ember usage, the `{{action}}` helper is usually the best + choice. This mixin is most often useful when you are doing more complex + event handling in custom View subclasses. + + For example: + + ```javascript + App.SaveButtonView = Ember.View.extend(Ember.ViewTargetActionSupport, { + action: 'save', + click: function() { + this.triggerAction(); // Sends the `save` action, along with the current context + // to the current controller + } + }); + ``` + + The `action` can be provided as properties of an optional object argument + to `triggerAction` as well. + + ```javascript + App.SaveButtonView = Ember.View.extend(Ember.ViewTargetActionSupport, { + click: function() { + this.triggerAction({ + action: 'save' + }); // Sends the `save` action, along with the current context + // to the current controller + } + }); + ``` + + @class ViewTargetActionSupport + @namespace Ember + @extends Ember.TargetActionSupport + */ + __exports__["default"] = Mixin.create(TargetActionSupport, { + /** + @property target + */ + target: alias('controller'), + /** + @property actionContext + */ + actionContext: alias('context') + }); + }); +enifed("ember-views/system/action_manager", + ["exports"], + function(__exports__) { + "use strict"; + /** + @module ember + @submodule ember-views + */ + + function ActionManager() {} + + /** + Global action id hash. + + @private + @property registeredActions + @type Object + */ + ActionManager.registeredActions = {}; + + __exports__["default"] = ActionManager; + }); +enifed("ember-views/system/event_dispatcher", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/is_none","ember-metal/run_loop","ember-metal/utils","ember-runtime/system/string","ember-runtime/system/object","ember-views/system/jquery","ember-views/system/action_manager","ember-views/views/view","ember-metal/merge","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-views + */ + var Ember = __dependency1__["default"]; + // Ember.assert + + var get = __dependency2__.get; + var set = __dependency3__.set; + var isNone = __dependency4__.isNone; + var run = __dependency5__["default"]; + var typeOf = __dependency6__.typeOf; + var fmt = __dependency7__.fmt; + var EmberObject = __dependency8__["default"]; + var jQuery = __dependency9__["default"]; + var ActionManager = __dependency10__["default"]; + var View = __dependency11__["default"]; + var merge = __dependency12__["default"]; + + //ES6TODO: + // find a better way to do Ember.View.views without global state + + /** + `Ember.EventDispatcher` handles delegating browser events to their + corresponding `Ember.Views.` For example, when you click on a view, + `Ember.EventDispatcher` ensures that that view's `mouseDown` method gets + called. + + @class EventDispatcher + @namespace Ember + @private + @extends Ember.Object + */ + __exports__["default"] = EmberObject.extend({ + + /** + The set of events names (and associated handler function names) to be setup + and dispatched by the `EventDispatcher`. Custom events can added to this list at setup + time, generally via the `Ember.Application.customEvents` hash. Only override this + default set to prevent the EventDispatcher from listening on some events all together. + + This set will be modified by `setup` to also include any events added at that time. + + @property events + @type Object + */ + events: { + touchstart : 'touchStart', + touchmove : 'touchMove', + touchend : 'touchEnd', + touchcancel : 'touchCancel', + keydown : 'keyDown', + keyup : 'keyUp', + keypress : 'keyPress', + mousedown : 'mouseDown', + mouseup : 'mouseUp', + contextmenu : 'contextMenu', + click : 'click', + dblclick : 'doubleClick', + mousemove : 'mouseMove', + focusin : 'focusIn', + focusout : 'focusOut', + mouseenter : 'mouseEnter', + mouseleave : 'mouseLeave', + submit : 'submit', + input : 'input', + change : 'change', + dragstart : 'dragStart', + drag : 'drag', + dragenter : 'dragEnter', + dragleave : 'dragLeave', + dragover : 'dragOver', + drop : 'drop', + dragend : 'dragEnd' + }, + + /** + The root DOM element to which event listeners should be attached. Event + listeners will be attached to the document unless this is overridden. + + Can be specified as a DOMElement or a selector string. + + The default body is a string since this may be evaluated before document.body + exists in the DOM. + + @private + @property rootElement + @type DOMElement + @default 'body' + */ + rootElement: 'body', + + /** + It enables events to be dispatched to the view's `eventManager.` When present, + this object takes precedence over handling of events on the view itself. + + Note that most Ember applications do not use this feature. If your app also + does not use it, consider setting this property to false to gain some performance + improvement by allowing the EventDispatcher to skip the search for the + `eventManager` on the view tree. + + ```javascript + var EventDispatcher = Em.EventDispatcher.extend({ + events: { + click : 'click', + focusin : 'focusIn', + focusout : 'focusOut', + change : 'change' + }, + canDispatchToEventManager: false + }); + container.register('event_dispatcher:main', EventDispatcher); + ``` + + @property canDispatchToEventManager + @type boolean + @default 'true' + @since 1.7.0 + */ + canDispatchToEventManager: true, + + /** + Sets up event listeners for standard browser events. + + This will be called after the browser sends a `DOMContentReady` event. By + default, it will set up all of the listeners on the document body. If you + would like to register the listeners on a different element, set the event + dispatcher's `root` property. + + @private + @method setup + @param addedEvents {Hash} + */ + setup: function(addedEvents, rootElement) { + var event, events = get(this, 'events'); + + merge(events, addedEvents || {}); + + if (!isNone(rootElement)) { + set(this, 'rootElement', rootElement); + } + + rootElement = jQuery(get(this, 'rootElement')); + + Ember.assert(fmt('You cannot use the same root element (%@) multiple times in an Ember.Application', [rootElement.selector || rootElement[0].tagName]), !rootElement.is('.ember-application')); + Ember.assert('You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', !rootElement.closest('.ember-application').length); + Ember.assert('You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', !rootElement.find('.ember-application').length); + + rootElement.addClass('ember-application'); + + Ember.assert('Unable to add "ember-application" class to rootElement. Make sure you set rootElement to the body or an element in the body.', rootElement.is('.ember-application')); + + for (event in events) { + if (events.hasOwnProperty(event)) { + this.setupHandler(rootElement, event, events[event]); + } + } + }, + + /** + Registers an event listener on the rootElement. If the given event is + triggered, the provided event handler will be triggered on the target view. + + If the target view does not implement the event handler, or if the handler + returns `false`, the parent view will be called. The event will continue to + bubble to each successive parent view until it reaches the top. + + @private + @method setupHandler + @param {Element} rootElement + @param {String} event the browser-originated event to listen to + @param {String} eventName the name of the method to call on the view + */ + setupHandler: function(rootElement, event, eventName) { + var self = this; + + rootElement.on(event + '.ember', '.ember-view', function(evt, triggeringManager) { + var view = View.views[this.id]; + var result = true; + + var manager = self.canDispatchToEventManager ? self._findNearestEventManager(view, eventName) : null; + + if (manager && manager !== triggeringManager) { + result = self._dispatchEvent(manager, evt, eventName, view); + } else if (view) { + result = self._bubbleEvent(view, evt, eventName); + } + + return result; + }); + + rootElement.on(event + '.ember', '[data-ember-action]', function(evt) { + var actionId = jQuery(evt.currentTarget).attr('data-ember-action'); + var action = ActionManager.registeredActions[actionId]; + + // We have to check for action here since in some cases, jQuery will trigger + // an event on `removeChild` (i.e. focusout) after we've already torn down the + // action handlers for the view. + if (action && action.eventName === eventName) { + return action.handler(evt); + } + }); + }, + + _findNearestEventManager: function(view, eventName) { + var manager = null; + + while (view) { + manager = get(view, 'eventManager'); + if (manager && manager[eventName]) { break; } + + view = get(view, 'parentView'); + } + + return manager; + }, + + _dispatchEvent: function(object, evt, eventName, view) { + var result = true; + + var handler = object[eventName]; + if (typeOf(handler) === 'function') { + result = run(object, handler, evt, view); + // Do not preventDefault in eventManagers. + evt.stopPropagation(); + } + else { + result = this._bubbleEvent(view, evt, eventName); + } + + return result; + }, + + _bubbleEvent: function(view, evt, eventName) { + return run(view, view.handleEvent, eventName, evt); + }, + + destroy: function() { + var rootElement = get(this, 'rootElement'); + jQuery(rootElement).off('.ember', '**').removeClass('ember-application'); + return this._super(); + }, + + toString: function() { + return '(EventDispatcher)'; + } + }); + }); +enifed("ember-views/system/ext", + ["ember-metal/run_loop"], + function(__dependency1__) { + "use strict"; + /** + @module ember + @submodule ember-views + */ + + var run = __dependency1__["default"]; + + // Add a new named queue for rendering views that happens + // after bindings have synced, and a queue for scheduling actions + // that that should occur after view rendering. + var queues = run.queues; + run._addQueue('render', 'actions'); + run._addQueue('afterRender', 'render'); + }); +enifed("ember-views/system/jquery", + ["ember-metal/core","ember-runtime/system/string","ember-metal/enumerable_utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert + var w = __dependency2__.w; + + // ES6TODO: the functions on EnumerableUtils need their own exports + var forEach = __dependency3__.forEach; + + /** + Ember Views + + @module ember + @submodule ember-views + @requires ember-runtime + @main ember-views + */ + + var jQuery = (Ember.imports && Ember.imports.jQuery) || (this && this.jQuery); + if (!jQuery && typeof eriuqer === 'function') { + jQuery = eriuqer('jquery'); + } + + Ember.assert("Ember Views require jQuery between 1.7 and 2.1", jQuery && (jQuery().jquery.match(/^((1\.(7|8|9|10|11))|(2\.(0|1)))(\.\d+)?(pre|rc\d?)?/) || Ember.ENV.FORCE_JQUERY)); + + /** + @module ember + @submodule ember-views + */ + if (jQuery) { + // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#dndevents + var dragEvents = w('dragstart drag dragenter dragleave dragover drop dragend'); + + // Copies the `dataTransfer` property from a browser event object onto the + // jQuery event object for the specified events + forEach(dragEvents, function(eventName) { + jQuery.event.fixHooks[eventName] = { props: ['dataTransfer'] }; + }); + } + + __exports__["default"] = jQuery; + }); +enifed("ember-views/system/render_buffer", + ["ember-views/system/jquery","morph","ember-metal/core","ember-metal/platform","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-views + */ + + var jQuery = __dependency1__["default"]; + var DOMHelper = __dependency2__.DOMHelper; + var Ember = __dependency3__["default"]; + var create = __dependency4__.create; + + // The HTML spec allows for "omitted start tags". These tags are optional + // when their intended child is the first thing in the parent tag. For + // example, this is a tbody start tag: + // + // + // + // + // + // The tbody may be omitted, and the browser will accept and render: + // + //
    + // + // + // However, the omitted start tag will still be added to the DOM. Here + // we test the string and context to see if the browser is about to + // perform this cleanup, but with a special allowance for disregarding + // + ``` + + And associate it by name using a view's `templateName` property: + + ```javascript + AView = Ember.View.extend({ + templateName: 'some-template' + }); + ``` + + If you have nested resources, your Handlebars template will look like this: + + ```html + + ``` + + And `templateName` property: + + ```javascript + AView = Ember.View.extend({ + templateName: 'posts/new' + }); + ``` + + Using a value for `templateName` that does not have a Handlebars template + with a matching `data-template-name` attribute will throw an error. + + For views classes that may have a template later defined (e.g. as the block + portion of a `{{view}}` Handlebars helper call in another template or in + a subclass), you can provide a `defaultTemplate` property set to compiled + template function. If a template is not later provided for the view instance + the `defaultTemplate` value will be used: + + ```javascript + AView = Ember.View.extend({ + defaultTemplate: Ember.Handlebars.compile('I was the default'), + template: null, + templateName: null + }); + ``` + + Will result in instances with an HTML representation of: + + ```html +
    I was the default
    + ``` + + If a `template` or `templateName` is provided it will take precedence over + `defaultTemplate`: + + ```javascript + AView = Ember.View.extend({ + defaultTemplate: Ember.Handlebars.compile('I was the default') + }); + + aView = AView.create({ + template: Ember.Handlebars.compile('I was the template, not default') + }); + ``` + + Will result in the following HTML representation when rendered: + + ```html +
    I was the template, not default
    + ``` + + ## View Context + + The default context of the compiled template is the view's controller: + + ```javascript + AView = Ember.View.extend({ + template: Ember.Handlebars.compile('Hello {{excitedGreeting}}') + }); + + aController = Ember.Object.create({ + firstName: 'Barry', + excitedGreeting: function() { + return this.get("content.firstName") + "!!!" + }.property() + }); + + aView = AView.create({ + controller: aController + }); + ``` + + Will result in an HTML representation of: + + ```html +
    Hello Barry!!!
    + ``` + + A context can also be explicitly supplied through the view's `context` + property. If the view has neither `context` nor `controller` properties, the + `parentView`'s context will be used. + + ## Layouts + + Views can have a secondary template that wraps their main template. Like + primary templates, layouts can be any function that accepts an optional + context parameter and returns a string of HTML that will be inserted inside + view's tag. Views whose HTML element is self closing (e.g. ``) + cannot have a layout and this property will be ignored. + + Most typically in Ember a layout will be a compiled `Ember.Handlebars` + template. + + A view's layout can be set directly with the `layout` property or reference + an existing Handlebars template by name with the `layoutName` property. + + A template used as a layout must contain a single use of the Handlebars + `{{yield}}` helper. The HTML contents of a view's rendered `template` will be + inserted at this location: + + ```javascript + AViewWithLayout = Ember.View.extend({ + layout: Ember.Handlebars.compile("
    {{yield}}
    "), + template: Ember.Handlebars.compile("I got wrapped") + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html +
    +
    + I got wrapped +
    +
    + ``` + + See [Ember.Handlebars.helpers.yield](/api/classes/Ember.Handlebars.helpers.html#method_yield) + for more information. + + ## Responding to Browser Events + + Views can respond to user-initiated events in one of three ways: method + implementation, through an event manager, and through `{{action}}` helper use + in their template or layout. + + ### Method Implementation + + Views can respond to user-initiated events by implementing a method that + matches the event name. A `jQuery.Event` object will be passed as the + argument to this method. + + ```javascript + AView = Ember.View.extend({ + click: function(event) { + // will be called when when an instance's + // rendered element is clicked + } + }); + ``` + + ### Event Managers + + Views can define an object as their `eventManager` property. This object can + then implement methods that match the desired event names. Matching events + that occur on the view's rendered HTML or the rendered HTML of any of its DOM + descendants will trigger this method. A `jQuery.Event` object will be passed + as the first argument to the method and an `Ember.View` object as the + second. The `Ember.View` will be the view whose rendered HTML was interacted + with. This may be the view with the `eventManager` property or one of its + descendent views. + + ```javascript + AView = Ember.View.extend({ + eventManager: Ember.Object.create({ + doubleClick: function(event, view) { + // will be called when when an instance's + // rendered element or any rendering + // of this views's descendent + // elements is clicked + } + }) + }); + ``` + + An event defined for an event manager takes precedence over events of the + same name handled through methods on the view. + + ```javascript + AView = Ember.View.extend({ + mouseEnter: function(event) { + // will never trigger. + }, + eventManager: Ember.Object.create({ + mouseEnter: function(event, view) { + // takes precedence over AView#mouseEnter + } + }) + }); + ``` + + Similarly a view's event manager will take precedence for events of any views + rendered as a descendent. A method name that matches an event name will not + be called if the view instance was rendered inside the HTML representation of + a view that has an `eventManager` property defined that handles events of the + name. Events not handled by the event manager will still trigger method calls + on the descendent. + + ```javascript + var App = Ember.Application.create(); + App.OuterView = Ember.View.extend({ + template: Ember.Handlebars.compile("outer {{#view 'inner'}}inner{{/view}} outer"), + eventManager: Ember.Object.create({ + mouseEnter: function(event, view) { + // view might be instance of either + // OuterView or InnerView depending on + // where on the page the user interaction occured + } + }) + }); + + App.InnerView = Ember.View.extend({ + click: function(event) { + // will be called if rendered inside + // an OuterView because OuterView's + // eventManager doesn't handle click events + }, + mouseEnter: function(event) { + // will never be called if rendered inside + // an OuterView. + } + }); + ``` + + ### Handlebars `{{action}}` Helper + + See [Handlebars.helpers.action](/api/classes/Ember.Handlebars.helpers.html#method_action). + + ### Event Names + + All of the event handling approaches described above respond to the same set + of events. The names of the built-in events are listed below. (The hash of + built-in events exists in `Ember.EventDispatcher`.) Additional, custom events + can be registered by using `Ember.Application.customEvents`. + + Touch events: + + * `touchStart` + * `touchMove` + * `touchEnd` + * `touchCancel` + + Keyboard events + + * `keyDown` + * `keyUp` + * `keyPress` + + Mouse events + + * `mouseDown` + * `mouseUp` + * `contextMenu` + * `click` + * `doubleClick` + * `mouseMove` + * `focusIn` + * `focusOut` + * `mouseEnter` + * `mouseLeave` + + Form events: + + * `submit` + * `change` + * `focusIn` + * `focusOut` + * `input` + + HTML5 drag and drop events: + + * `dragStart` + * `drag` + * `dragEnter` + * `dragLeave` + * `dragOver` + * `dragEnd` + * `drop` + + ## Handlebars `{{view}}` Helper + + Other `Ember.View` instances can be included as part of a view's template by + using the `{{view}}` Handlebars helper. See [Ember.Handlebars.helpers.view](/api/classes/Ember.Handlebars.helpers.html#method_view) + for additional information. + + @class View + @namespace Ember + @extends Ember.CoreView + */ + var View = CoreView.extend({ + + concatenatedProperties: ['classNames', 'classNameBindings', 'attributeBindings'], + + /** + @property isView + @type Boolean + @default true + @static + */ + isView: true, + + // .......................................................... + // TEMPLATE SUPPORT + // + + /** + The name of the template to lookup if no template is provided. + + By default `Ember.View` will lookup a template with this name in + `Ember.TEMPLATES` (a shared global object). + + @property templateName + @type String + @default null + */ + templateName: null, + + /** + The name of the layout to lookup if no layout is provided. + + By default `Ember.View` will lookup a template with this name in + `Ember.TEMPLATES` (a shared global object). + + @property layoutName + @type String + @default null + */ + layoutName: null, + + /** + Used to identify this view during debugging + + @property instrumentDisplay + @type String + */ + instrumentDisplay: computed(function() { + if (this.helperName) { + return '{{' + this.helperName + '}}'; + } + }), + + /** + The template used to render the view. This should be a function that + accepts an optional context parameter and returns a string of HTML that + will be inserted into the DOM relative to its parent view. + + In general, you should set the `templateName` property instead of setting + the template yourself. + + @property template + @type Function + */ + template: computed('templateName', function(key, value) { + if (value !== undefined) { return value; } + + var templateName = get(this, 'templateName'); + var template = this.templateForName(templateName, 'template'); + + Ember.assert("You specified the templateName " + templateName + " for " + this + ", but it did not exist.", !templateName || template); + + return template || get(this, 'defaultTemplate'); + }), + + /** + The controller managing this view. If this property is set, it will be + made available for use by the template. + + @property controller + @type Object + */ + controller: computed('_parentView', function(key) { + var parentView = get(this, '_parentView'); + return parentView ? get(parentView, 'controller') : null; + }), + + /** + A view may contain a layout. A layout is a regular template but + supersedes the `template` property during rendering. It is the + responsibility of the layout template to retrieve the `template` + property from the view (or alternatively, call `Handlebars.helpers.yield`, + `{{yield}}`) to render it in the correct location. + + This is useful for a view that has a shared wrapper, but which delegates + the rendering of the contents of the wrapper to the `template` property + on a subclass. + + @property layout + @type Function + */ + layout: computed(function(key) { + var layoutName = get(this, 'layoutName'); + var layout = this.templateForName(layoutName, 'layout'); + + Ember.assert("You specified the layoutName " + layoutName + " for " + this + ", but it did not exist.", !layoutName || layout); + + return layout || get(this, 'defaultLayout'); + }).property('layoutName'), + + _yield: function(context, options) { + var template = get(this, 'template'); + if (template) { template(context, options); } + }, + + templateForName: function(name, type) { + if (!name) { return; } + Ember.assert("templateNames are not allowed to contain periods: "+name, name.indexOf('.') === -1); + + if (!this.container) { + throw new EmberError('Container was not found when looking up a views template. ' + + 'This is most likely due to manually instantiating an Ember.View. ' + + 'See: http://git.io/EKPpnA'); + } + + return this.container.lookup('template:' + name); + }, + + /** + The object from which templates should access properties. + + This object will be passed to the template function each time the render + method is called, but it is up to the individual function to decide what + to do with it. + + By default, this will be the view's controller. + + @property context + @type Object + */ + context: computed(function(key, value) { + if (arguments.length === 2) { + set(this, '_context', value); + return value; + } else { + return get(this, '_context'); + } + })["volatile"](), + + /** + Private copy of the view's template context. This can be set directly + by Handlebars without triggering the observer that causes the view + to be re-rendered. + + The context of a view is looked up as follows: + + 1. Supplied context (usually by Handlebars) + 2. Specified controller + 3. `parentView`'s context (for a child of a ContainerView) + + The code in Handlebars that overrides the `_context` property first + checks to see whether the view has a specified controller. This is + something of a hack and should be revisited. + + @property _context + @private + */ + _context: computed(function(key) { + var parentView, controller; + + if (controller = get(this, 'controller')) { + return controller; + } + + parentView = this._parentView; + if (parentView) { + return get(parentView, '_context'); + } + + return null; + }), + + /** + If a value that affects template rendering changes, the view should be + re-rendered to reflect the new value. + + @method _contextDidChange + @private + */ + _contextDidChange: observer('context', function() { + this.rerender(); + }), + + /** + If `false`, the view will appear hidden in DOM. + + @property isVisible + @type Boolean + @default null + */ + isVisible: true, + + /** + Array of child views. You should never edit this array directly. + Instead, use `appendChild` and `removeFromParent`. + + @property childViews + @type Array + @default [] + @private + */ + childViews: childViewsProperty, + + _childViews: EMPTY_ARRAY, + + // When it's a virtual view, we need to notify the parent that their + // childViews will change. + _childViewsWillChange: beforeObserver('childViews', function() { + if (this.isVirtual) { + var parentView = get(this, 'parentView'); + if (parentView) { propertyWillChange(parentView, 'childViews'); } + } + }), + + // When it's a virtual view, we need to notify the parent that their + // childViews did change. + _childViewsDidChange: observer('childViews', function() { + if (this.isVirtual) { + var parentView = get(this, 'parentView'); + if (parentView) { propertyDidChange(parentView, 'childViews'); } + } + }), + + /** + Return the nearest ancestor that is an instance of the provided + class. + + @method nearestInstanceOf + @param {Class} klass Subclass of Ember.View (or Ember.View itself) + @return Ember.View + @deprecated + */ + nearestInstanceOf: function(klass) { + Ember.deprecate("nearestInstanceOf is deprecated and will be removed from future releases. Use nearestOfType."); + var view = get(this, 'parentView'); + + while (view) { + if (view instanceof klass) { return view; } + view = get(view, 'parentView'); + } + }, + + /** + Return the nearest ancestor that is an instance of the provided + class or mixin. + + @method nearestOfType + @param {Class,Mixin} klass Subclass of Ember.View (or Ember.View itself), + or an instance of Ember.Mixin. + @return Ember.View + */ + nearestOfType: function(klass) { + var view = get(this, 'parentView'); + var isOfType = klass instanceof Mixin ? + function(view) { return klass.detect(view); } : + function(view) { return klass.detect(view.constructor); }; + + while (view) { + if (isOfType(view)) { return view; } + view = get(view, 'parentView'); + } + }, + + /** + Return the nearest ancestor that has a given property. + + @method nearestWithProperty + @param {String} property A property name + @return Ember.View + */ + nearestWithProperty: function(property) { + var view = get(this, 'parentView'); + + while (view) { + if (property in view) { return view; } + view = get(view, 'parentView'); + } + }, + + /** + Return the nearest ancestor whose parent is an instance of + `klass`. + + @method nearestChildOf + @param {Class} klass Subclass of Ember.View (or Ember.View itself) + @return Ember.View + */ + nearestChildOf: function(klass) { + var view = get(this, 'parentView'); + + while (view) { + if (get(view, 'parentView') instanceof klass) { return view; } + view = get(view, 'parentView'); + } + }, + + /** + When the parent view changes, recursively invalidate `controller` + + @method _parentViewDidChange + @private + */ + _parentViewDidChange: observer('_parentView', function() { + if (this.isDestroying) { return; } + + this.trigger('parentViewDidChange'); + + if (get(this, 'parentView.controller') && !get(this, 'controller')) { + this.notifyPropertyChange('controller'); + } + }), + + _controllerDidChange: observer('controller', function() { + if (this.isDestroying) { return; } + + this.rerender(); + + this.forEachChildView(function(view) { + view.propertyDidChange('controller'); + }); + }), + + cloneKeywords: function() { + var templateData = get(this, 'templateData'); + + var keywords = templateData ? copy(templateData.keywords) : {}; + set(keywords, 'view', this.isVirtual ? keywords.view : this); + set(keywords, '_view', this); + set(keywords, 'controller', get(this, 'controller')); + + return keywords; + }, + + /** + Called on your view when it should push strings of HTML into a + `Ember.RenderBuffer`. Most users will want to override the `template` + or `templateName` properties instead of this method. + + By default, `Ember.View` will look for a function in the `template` + property and invoke it with the value of `context`. The value of + `context` will be the view's controller unless you override it. + + @method render + @param {Ember.RenderBuffer} buffer The render buffer + */ + render: function(buffer) { + // If this view has a layout, it is the responsibility of the + // the layout to render the view's template. Otherwise, render the template + // directly. + var template = get(this, 'layout') || get(this, 'template'); + + if (template) { + var context = get(this, 'context'); + var keywords = this.cloneKeywords(); + var output; + + var data = { + view: this, + buffer: buffer, + isRenderData: true, + keywords: keywords, + insideGroup: get(this, 'templateData.insideGroup') + }; + + // Invoke the template with the provided template context, which + // is the view's controller by default. A hash of data is also passed that provides + // the template with access to the view and render buffer. + + Ember.assert('template must be a function. Did you mean to call Ember.Handlebars.compile("...") or specify templateName instead?', typeof template === 'function'); + // The template should write directly to the render buffer instead + // of returning a string. + output = template(context, { data: data }); + + // If the template returned a string instead of writing to the buffer, + // push the string onto the buffer. + if (output !== undefined) { buffer.push(output); } + } + }, + + /** + Renders the view again. This will work regardless of whether the + view is already in the DOM or not. If the view is in the DOM, the + rendering process will be deferred to give bindings a chance + to synchronize. + + If children were added during the rendering process using `appendChild`, + `rerender` will remove them, because they will be added again + if needed by the next `render`. + + In general, if the display of your view changes, you should modify + the DOM element directly instead of manually calling `rerender`, which can + be slow. + + @method rerender + */ + rerender: function() { + return this.currentState.rerender(this); + }, + + /** + Iterates over the view's `classNameBindings` array, inserts the value + of the specified property into the `classNames` array, then creates an + observer to update the view's element if the bound property ever changes + in the future. + + @method _applyClassNameBindings + @private + */ + _applyClassNameBindings: function(classBindings) { + var classNames = this.classNames; + var elem, newClass, dasherizedClass; + + // Loop through all of the configured bindings. These will be either + // property names ('isUrgent') or property paths relative to the view + // ('content.isUrgent') + forEach(classBindings, function(binding) { + + Ember.assert("classNameBindings must not have spaces in them. Multiple class name bindings can be provided as elements of an array, e.g. ['foo', ':bar']", binding.indexOf(' ') === -1); + + // Variable in which the old class value is saved. The observer function + // closes over this variable, so it knows which string to remove when + // the property changes. + var oldClass; + // Extract just the property name from bindings like 'foo:bar' + var parsedPath = View._parsePropertyPath(binding); + + // Set up an observer on the context. If the property changes, toggle the + // class name. + var observer = function() { + // Get the current value of the property + newClass = this._classStringForProperty(binding); + elem = this.$(); + + // If we had previously added a class to the element, remove it. + if (oldClass) { + elem.removeClass(oldClass); + // Also remove from classNames so that if the view gets rerendered, + // the class doesn't get added back to the DOM. + classNames.removeObject(oldClass); + } + + // If necessary, add a new class. Make sure we keep track of it so + // it can be removed in the future. + if (newClass) { + elem.addClass(newClass); + oldClass = newClass; + } else { + oldClass = null; + } + }; + + // Get the class name for the property at its current value + dasherizedClass = this._classStringForProperty(binding); + + if (dasherizedClass) { + // Ensure that it gets into the classNames array + // so it is displayed when we render. + addObject(classNames, dasherizedClass); + + // Save a reference to the class name so we can remove it + // if the observer fires. Remember that this variable has + // been closed over by the observer. + oldClass = dasherizedClass; + } + + this.registerObserver(this, parsedPath.path, observer); + // Remove className so when the view is rerendered, + // the className is added based on binding reevaluation + this.one('willClearRender', function() { + if (oldClass) { + classNames.removeObject(oldClass); + oldClass = null; + } + }); + + }, this); + }, + + _unspecifiedAttributeBindings: null, + + /** + Iterates through the view's attribute bindings, sets up observers for each, + then applies the current value of the attributes to the passed render buffer. + + @method _applyAttributeBindings + @param {Ember.RenderBuffer} buffer + @private + */ + _applyAttributeBindings: function(buffer, attributeBindings) { + var attributeValue; + var unspecifiedAttributeBindings = this._unspecifiedAttributeBindings = this._unspecifiedAttributeBindings || {}; + + forEach(attributeBindings, function(binding) { + var split = binding.split(':'); + var property = split[0]; + var attributeName = split[1] || property; + + if (property in this) { + this._setupAttributeBindingObservation(property, attributeName); + + // Determine the current value and add it to the render buffer + // if necessary. + attributeValue = get(this, property); + View.applyAttributeBindings(buffer, attributeName, attributeValue); + } else { + unspecifiedAttributeBindings[property] = attributeName; + } + }, this); + + // Lazily setup setUnknownProperty after attributeBindings are initially applied + this.setUnknownProperty = this._setUnknownProperty; + }, + + _setupAttributeBindingObservation: function(property, attributeName) { + var attributeValue, elem; + + // Create an observer to add/remove/change the attribute if the + // JavaScript property changes. + var observer = function() { + elem = this.$(); + + attributeValue = get(this, property); + + View.applyAttributeBindings(elem, attributeName, attributeValue); + }; + + this.registerObserver(this, property, observer); + }, + + /** + We're using setUnknownProperty as a hook to setup attributeBinding observers for + properties that aren't defined on a view at initialization time. + + Note: setUnknownProperty will only be called once for each property. + + @method setUnknownProperty + @param key + @param value + @private + */ + setUnknownProperty: null, // Gets defined after initialization by _applyAttributeBindings + + _setUnknownProperty: function(key, value) { + var attributeName = this._unspecifiedAttributeBindings && this._unspecifiedAttributeBindings[key]; + if (attributeName) { + this._setupAttributeBindingObservation(key, attributeName); + } + + defineProperty(this, key); + return set(this, key, value); + }, + + /** + Given a property name, returns a dasherized version of that + property name if the property evaluates to a non-falsy value. + + For example, if the view has property `isUrgent` that evaluates to true, + passing `isUrgent` to this method will return `"is-urgent"`. + + @method _classStringForProperty + @param property + @private + */ + _classStringForProperty: function(property) { + var parsedPath = View._parsePropertyPath(property); + var path = parsedPath.path; + + var val = get(this, path); + if (val === undefined && isGlobalPath(path)) { + val = get(Ember.lookup, path); + } + + return View._classStringForValue(path, val, parsedPath.className, parsedPath.falsyClassName); + }, + + // .......................................................... + // ELEMENT SUPPORT + // + + /** + Returns the current DOM element for the view. + + @property element + @type DOMElement + */ + element: null, + + /** + Returns a jQuery object for this view's element. If you pass in a selector + string, this method will return a jQuery object, using the current element + as its buffer. + + For example, calling `view.$('li')` will return a jQuery object containing + all of the `li` elements inside the DOM element of this view. + + @method $ + @param {String} [selector] a jQuery-compatible selector string + @return {jQuery} the jQuery object for the DOM node + */ + $: function(sel) { + return this.currentState.$(this, sel); + }, + + mutateChildViews: function(callback) { + var childViews = this._childViews; + var idx = childViews.length; + var view; + + while(--idx >= 0) { + view = childViews[idx]; + callback(this, view, idx); + } + + return this; + }, + + forEachChildView: function(callback) { + var childViews = this._childViews; + + if (!childViews) { return this; } + + var len = childViews.length; + var view, idx; + + for (idx = 0; idx < len; idx++) { + view = childViews[idx]; + callback(view); + } + + return this; + }, + + /** + Appends the view's element to the specified parent element. + + If the view does not have an HTML representation yet, `createElement()` + will be called automatically. + + Note that this method just schedules the view to be appended; the DOM + element will not be appended to the given element until all bindings have + finished synchronizing. + + This is not typically a function that you will need to call directly when + building your application. You might consider using `Ember.ContainerView` + instead. If you do need to use `appendTo`, be sure that the target element + you are providing is associated with an `Ember.Application` and does not + have an ancestor element that is associated with an Ember view. + + @method appendTo + @param {String|DOMElement|jQuery} A selector, element, HTML string, or jQuery object + @return {Ember.View} receiver + */ + appendTo: function(selector) { + var target = jQuery(selector); + + Ember.assert("You tried to append to (" + selector + ") but that isn't in the DOM", target.length > 0); + Ember.assert("You cannot append to an existing Ember.View. Consider using Ember.ContainerView instead.", !target.is('.ember-view') && !target.parents().is('.ember-view')); + + this.constructor.renderer.appendTo(this, target[0]); + + return this; + }, + + /** + Replaces the content of the specified parent element with this view's + element. If the view does not have an HTML representation yet, + `createElement()` will be called automatically. + + Note that this method just schedules the view to be appended; the DOM + element will not be appended to the given element until all bindings have + finished synchronizing + + @method replaceIn + @param {String|DOMElement|jQuery} target A selector, element, HTML string, or jQuery object + @return {Ember.View} received + */ + replaceIn: function(selector) { + var target = jQuery(selector); + + Ember.assert("You tried to replace in (" + selector + ") but that isn't in the DOM", target.length > 0); + Ember.assert("You cannot replace an existing Ember.View. Consider using Ember.ContainerView instead.", !target.is('.ember-view') && !target.parents().is('.ember-view')); + + this.constructor.renderer.replaceIn(this, target[0]); + + return this; + }, + + /** + Appends the view's element to the document body. If the view does + not have an HTML representation yet, `createElement()` will be called + automatically. + + If your application uses the `rootElement` property, you must append + the view within that element. Rendering views outside of the `rootElement` + is not supported. + + Note that this method just schedules the view to be appended; the DOM + element will not be appended to the document body until all bindings have + finished synchronizing. + + @method append + @return {Ember.View} receiver + */ + append: function() { + return this.appendTo(document.body); + }, + + /** + Removes the view's element from the element to which it is attached. + + @method remove + @return {Ember.View} receiver + */ + remove: function() { + // What we should really do here is wait until the end of the run loop + // to determine if the element has been re-appended to a different + // element. + // In the interim, we will just re-render if that happens. It is more + // important than elements get garbage collected. + if (!this.removedFromDOM) { this.destroyElement(); } + }, + + elementId: null, + + /** + Attempts to discover the element in the parent element. The default + implementation looks for an element with an ID of `elementId` (or the + view's guid if `elementId` is null). You can override this method to + provide your own form of lookup. For example, if you want to discover your + element using a CSS class name instead of an ID. + + @method findElementInParentElement + @param {DOMElement} parentElement The parent's DOM element + @return {DOMElement} The discovered element + */ + findElementInParentElement: function(parentElem) { + var id = "#" + this.elementId; + return jQuery(id)[0] || jQuery(id, parentElem)[0]; + }, + + /** + Creates a DOM representation of the view and all of its child views by + recursively calling the `render()` method. + + After the element has been inserted into the DOM, `didInsertElement` will + be called on this view and all of its child views. + + @method createElement + @return {Ember.View} receiver + */ + createElement: function() { + if (this.element) { return this; } + + this._didCreateElementWithoutMorph = true; + this.constructor.renderer.renderTree(this); + + return this; + }, + + /** + Called when a view is going to insert an element into the DOM. + + @event willInsertElement + */ + willInsertElement: Ember.K, + + /** + Called when the element of the view has been inserted into the DOM + or after the view was re-rendered. Override this function to do any + set up that requires an element in the document body. + + When a view has children, didInsertElement will be called on the + child view(s) first, bubbling upwards through the hierarchy. + + @event didInsertElement + */ + didInsertElement: Ember.K, + + /** + Called when the view is about to rerender, but before anything has + been torn down. This is a good opportunity to tear down any manual + observers you have installed based on the DOM state + + @event willClearRender + */ + willClearRender: Ember.K, + + /** + Destroys any existing element along with the element for any child views + as well. If the view does not currently have a element, then this method + will do nothing. + + If you implement `willDestroyElement()` on your view, then this method will + be invoked on your view before your element is destroyed to give you a + chance to clean up any event handlers, etc. + + If you write a `willDestroyElement()` handler, you can assume that your + `didInsertElement()` handler was called earlier for the same element. + + You should not call or override this method yourself, but you may + want to implement the above callbacks. + + @method destroyElement + @return {Ember.View} receiver + */ + destroyElement: function() { + return this.currentState.destroyElement(this); + }, + + /** + Called when the element of the view is going to be destroyed. Override + this function to do any teardown that requires an element, like removing + event listeners. + + Please note: any property changes made during this event will have no + effect on object observers. + + @event willDestroyElement + */ + willDestroyElement: Ember.K, + + /** + Called when the parentView property has changed. + + @event parentViewDidChange + */ + parentViewDidChange: Ember.K, + + instrumentName: 'view', + + instrumentDetails: function(hash) { + hash.template = get(this, 'templateName'); + this._super(hash); + }, + + beforeRender: function(buffer) {}, + + afterRender: function(buffer) {}, + + applyAttributesToBuffer: function(buffer) { + // Creates observers for all registered class name and attribute bindings, + // then adds them to the element. + var classNameBindings = get(this, 'classNameBindings'); + if (classNameBindings.length) { + this._applyClassNameBindings(classNameBindings); + } + + // Pass the render buffer so the method can apply attributes directly. + // This isn't needed for class name bindings because they use the + // existing classNames infrastructure. + var attributeBindings = get(this, 'attributeBindings'); + if (attributeBindings.length) { + this._applyAttributeBindings(buffer, attributeBindings); + } + + buffer.setClasses(this.classNames); + buffer.id(this.elementId); + + var role = get(this, 'ariaRole'); + if (role) { + buffer.attr('role', role); + } + + if (get(this, 'isVisible') === false) { + buffer.style('display', 'none'); + } + }, + + // .......................................................... + // STANDARD RENDER PROPERTIES + // + + /** + Tag name for the view's outer element. The tag name is only used when an + element is first created. If you change the `tagName` for an element, you + must destroy and recreate the view element. + + By default, the render buffer will use a `
    ` tag for views. + + @property tagName + @type String + @default null + */ + + // We leave this null by default so we can tell the difference between + // the default case and a user-specified tag. + tagName: null, + + /** + The WAI-ARIA role of the control represented by this view. For example, a + button may have a role of type 'button', or a pane may have a role of + type 'alertdialog'. This property is used by assistive software to help + visually challenged users navigate rich web applications. + + The full list of valid WAI-ARIA roles is available at: + [http://www.w3.org/TR/wai-aria/roles#roles_categorization](http://www.w3.org/TR/wai-aria/roles#roles_categorization) + + @property ariaRole + @type String + @default null + */ + ariaRole: null, + + /** + Standard CSS class names to apply to the view's outer element. This + property automatically inherits any class names defined by the view's + superclasses as well. + + @property classNames + @type Array + @default ['ember-view'] + */ + classNames: ['ember-view'], + + /** + A list of properties of the view to apply as class names. If the property + is a string value, the value of that string will be applied as a class + name. + + ```javascript + // Applies the 'high' class to the view element + Ember.View.extend({ + classNameBindings: ['priority'] + priority: 'high' + }); + ``` + + If the value of the property is a Boolean, the name of that property is + added as a dasherized class name. + + ```javascript + // Applies the 'is-urgent' class to the view element + Ember.View.extend({ + classNameBindings: ['isUrgent'] + isUrgent: true + }); + ``` + + If you would prefer to use a custom value instead of the dasherized + property name, you can pass a binding like this: + + ```javascript + // Applies the 'urgent' class to the view element + Ember.View.extend({ + classNameBindings: ['isUrgent:urgent'] + isUrgent: true + }); + ``` + + This list of properties is inherited from the view's superclasses as well. + + @property classNameBindings + @type Array + @default [] + */ + classNameBindings: EMPTY_ARRAY, + + /** + A list of properties of the view to apply as attributes. If the property is + a string value, the value of that string will be applied as the attribute. + + ```javascript + // Applies the type attribute to the element + // with the value "button", like
    + Ember.View.extend({ + attributeBindings: ['type'], + type: 'button' + }); + ``` + + If the value of the property is a Boolean, the name of that property is + added as an attribute. + + ```javascript + // Renders something like
    + Ember.View.extend({ + attributeBindings: ['enabled'], + enabled: true + }); + ``` + + @property attributeBindings + */ + attributeBindings: EMPTY_ARRAY, + + // ....................................................... + // CORE DISPLAY METHODS + // + + /** + Setup a view, but do not finish waking it up. + + * configure `childViews` + * register the view with the global views hash, which is used for event + dispatch + + @method init + @private + */ + init: function() { + if (!this.isVirtual && !this.elementId) { + this.elementId = guidFor(this); + } + + this._super(); + + // setup child views. be sure to clone the child views array first + this._childViews = this._childViews.slice(); + + Ember.assert("Only arrays are allowed for 'classNameBindings'", typeOf(this.classNameBindings) === 'array'); + this.classNameBindings = emberA(this.classNameBindings.slice()); + + Ember.assert("Only arrays are allowed for 'classNames'", typeOf(this.classNames) === 'array'); + this.classNames = emberA(this.classNames.slice()); + }, + + appendChild: function(view, options) { + return this.currentState.appendChild(this, view, options); + }, + + /** + Removes the child view from the parent view. + + @method removeChild + @param {Ember.View} view + @return {Ember.View} receiver + */ + removeChild: function(view) { + // If we're destroying, the entire subtree will be + // freed, and the DOM will be handled separately, + // so no need to mess with childViews. + if (this.isDestroying) { return; } + + // update parent node + set(view, '_parentView', null); + + // remove view from childViews array. + var childViews = this._childViews; + + removeObject(childViews, view); + + this.propertyDidChange('childViews'); // HUH?! what happened to will change? + + return this; + }, + + /** + Removes all children from the `parentView`. + + @method removeAllChildren + @return {Ember.View} receiver + */ + removeAllChildren: function() { + return this.mutateChildViews(function(parentView, view) { + parentView.removeChild(view); + }); + }, + + destroyAllChildren: function() { + return this.mutateChildViews(function(parentView, view) { + view.destroy(); + }); + }, + + /** + Removes the view from its `parentView`, if one is found. Otherwise + does nothing. + + @method removeFromParent + @return {Ember.View} receiver + */ + removeFromParent: function() { + var parent = this._parentView; + + // Remove DOM element from parent + this.remove(); + + if (parent) { parent.removeChild(this); } + return this; + }, + + /** + You must call `destroy` on a view to destroy the view (and all of its + child views). This will remove the view from any parent node, then make + sure that the DOM element managed by the view can be released by the + memory manager. + + @method destroy + */ + destroy: function() { + var childViews = this._childViews; + // get parentView before calling super because it'll be destroyed + var nonVirtualParentView = get(this, 'parentView'); + var viewName = this.viewName; + var childLen, i; + + if (!this._super()) { return; } + + // remove from non-virtual parent view if viewName was specified + if (viewName && nonVirtualParentView) { + nonVirtualParentView.set(viewName, null); + } + + return this; + }, + + /** + Instantiates a view to be added to the childViews array during view + initialization. You generally will not call this method directly unless + you are overriding `createChildViews()`. Note that this method will + automatically configure the correct settings on the new view instance to + act as a child of the parent. + + @method createChildView + @param {Class|String} viewClass + @param {Hash} [attrs] Attributes to add + @return {Ember.View} new instance + */ + createChildView: function(view, attrs) { + if (!view) { + throw new TypeError("createChildViews first argument must exist"); + } + + if (view.isView && view._parentView === this && view.container === this.container) { + return view; + } + + attrs = attrs || {}; + attrs._parentView = this; + + if (CoreView.detect(view)) { + attrs.templateData = attrs.templateData || get(this, 'templateData'); + + attrs.container = this.container; + view = view.create(attrs); + + // don't set the property on a virtual view, as they are invisible to + // consumers of the view API + if (view.viewName) { + set(get(this, 'concreteView'), view.viewName, view); + } + } else if ('string' === typeof view) { + var fullName = 'view:' + view; + var ViewKlass = this.container.lookupFactory(fullName); + + Ember.assert("Could not find view: '" + fullName + "'", !!ViewKlass); + + attrs.templateData = get(this, 'templateData'); + view = ViewKlass.create(attrs); + } else { + Ember.assert('You must pass instance or subclass of View', view.isView); + attrs.container = this.container; + + if (!get(view, 'templateData')) { + attrs.templateData = get(this, 'templateData'); + } + + setProperties(view, attrs); + + } + + return view; + }, + + becameVisible: Ember.K, + becameHidden: Ember.K, + + /** + When the view's `isVisible` property changes, toggle the visibility + element of the actual DOM element. + + @method _isVisibleDidChange + @private + */ + _isVisibleDidChange: observer('isVisible', function() { + if (this._isVisible === get(this, 'isVisible')) { return ; } + run.scheduleOnce('render', this, this._toggleVisibility); + }), + + _toggleVisibility: function() { + var $el = this.$(); + var isVisible = get(this, 'isVisible'); + + if (this._isVisible === isVisible) { return ; } + + // It's important to keep these in sync, even if we don't yet have + // an element in the DOM to manipulate: + this._isVisible = isVisible; + + if (!$el) { return; } + + $el.toggle(isVisible); + + if (this._isAncestorHidden()) { return; } + + if (isVisible) { + this._notifyBecameVisible(); + } else { + this._notifyBecameHidden(); + } + }, + + _notifyBecameVisible: function() { + this.trigger('becameVisible'); + + this.forEachChildView(function(view) { + var isVisible = get(view, 'isVisible'); + + if (isVisible || isVisible === null) { + view._notifyBecameVisible(); + } + }); + }, + + _notifyBecameHidden: function() { + this.trigger('becameHidden'); + this.forEachChildView(function(view) { + var isVisible = get(view, 'isVisible'); + + if (isVisible || isVisible === null) { + view._notifyBecameHidden(); + } + }); + }, + + _isAncestorHidden: function() { + var parent = get(this, 'parentView'); + + while (parent) { + if (get(parent, 'isVisible') === false) { return true; } + + parent = get(parent, 'parentView'); + } + + return false; + }, + transitionTo: function(state, children) { + Ember.deprecate("Ember.View#transitionTo has been deprecated, it is for internal use only"); + this._transitionTo(state, children); + }, + _transitionTo: function(state, children) { + var priorState = this.currentState; + var currentState = this.currentState = this._states[state]; + this._state = state; + + if (priorState && priorState.exit) { priorState.exit(this); } + if (currentState.enter) { currentState.enter(this); } + }, + + // ....................................................... + // EVENT HANDLING + // + + /** + Handle events from `Ember.EventDispatcher` + + @method handleEvent + @param eventName {String} + @param evt {Event} + @private + */ + handleEvent: function(eventName, evt) { + return this.currentState.handleEvent(this, eventName, evt); + }, + + registerObserver: function(root, path, target, observer) { + if (!observer && 'function' === typeof target) { + observer = target; + target = null; + } + + if (!root || typeof root !== 'object') { + return; + } + + var view = this; + var stateCheckedObserver = function() { + view.currentState.invokeObserver(this, observer); + }; + var scheduledObserver = function() { + run.scheduleOnce('render', this, stateCheckedObserver); + }; + + addObserver(root, path, target, scheduledObserver); + + this.one('willClearRender', function() { + removeObserver(root, path, target, scheduledObserver); + }); + } + + }); + deprecateProperty(View.prototype, 'state', '_state'); + deprecateProperty(View.prototype, 'states', '_states'); + + /* + Describe how the specified actions should behave in the various + states that a view can exist in. Possible states: + + * preRender: when a view is first instantiated, and after its + element was destroyed, it is in the preRender state + * inBuffer: once a view has been rendered, but before it has + been inserted into the DOM, it is in the inBuffer state + * hasElement: the DOM representation of the view is created, + and is ready to be inserted + * inDOM: once a view has been inserted into the DOM it is in + the inDOM state. A view spends the vast majority of its + existence in this state. + * destroyed: once a view has been destroyed (using the destroy + method), it is in this state. No further actions can be invoked + on a destroyed view. + */ + + // in the destroyed state, everything is illegal + + // before rendering has begun, all legal manipulations are noops. + + // inside the buffer, legal manipulations are done on the buffer + + // once the view has been inserted into the DOM, legal manipulations + // are done on the DOM element. + + function notifyMutationListeners() { + run.once(View, 'notifyMutationListeners'); + } + + View.reopenClass({ + + /** + Parse a path and return an object which holds the parsed properties. + + For example a path like "content.isEnabled:enabled:disabled" will return the + following object: + + ```javascript + { + path: "content.isEnabled", + className: "enabled", + falsyClassName: "disabled", + classNames: ":enabled:disabled" + } + ``` + + @method _parsePropertyPath + @static + @private + */ + _parsePropertyPath: function(path) { + var split = path.split(':'); + var propertyPath = split[0]; + var classNames = ""; + var className, falsyClassName; + + // check if the property is defined as prop:class or prop:trueClass:falseClass + if (split.length > 1) { + className = split[1]; + if (split.length === 3) { falsyClassName = split[2]; } + + classNames = ':' + className; + if (falsyClassName) { classNames += ":" + falsyClassName; } + } + + return { + path: propertyPath, + classNames: classNames, + className: (className === '') ? undefined : className, + falsyClassName: falsyClassName + }; + }, + + /** + Get the class name for a given value, based on the path, optional + `className` and optional `falsyClassName`. + + - if a `className` or `falsyClassName` has been specified: + - if the value is truthy and `className` has been specified, + `className` is returned + - if the value is falsy and `falsyClassName` has been specified, + `falsyClassName` is returned + - otherwise `null` is returned + - if the value is `true`, the dasherized last part of the supplied path + is returned + - if the value is not `false`, `undefined` or `null`, the `value` + is returned + - if none of the above rules apply, `null` is returned + + @method _classStringForValue + @param path + @param val + @param className + @param falsyClassName + @static + @private + */ + _classStringForValue: function(path, val, className, falsyClassName) { + if(isArray(val)) { + val = get(val, 'length') !== 0; + } + + // When using the colon syntax, evaluate the truthiness or falsiness + // of the value to determine which className to return + if (className || falsyClassName) { + if (className && !!val) { + return className; + + } else if (falsyClassName && !val) { + return falsyClassName; + + } else { + return null; + } + + // If value is a Boolean and true, return the dasherized property + // name. + } else if (val === true) { + // Normalize property path to be suitable for use + // as a class name. For exaple, content.foo.barBaz + // becomes bar-baz. + var parts = path.split('.'); + return dasherize(parts[parts.length-1]); + + // If the value is not false, undefined, or null, return the current + // value of the property. + } else if (val !== false && val != null) { + return val; + + // Nothing to display. Return null so that the old class is removed + // but no new class is added. + } else { + return null; + } + } + }); + + var mutation = EmberObject.extend(Evented).create(); + // TODO MOVE TO RENDERER HOOKS + View.addMutationListener = function(callback) { + mutation.on('change', callback); + }; + + View.removeMutationListener = function(callback) { + mutation.off('change', callback); + }; + + View.notifyMutationListeners = function() { + mutation.trigger('change'); + }; + + /** + Global views hash + + @property views + @static + @type Hash + */ + View.views = {}; + + // If someone overrides the child views computed property when + // defining their class, we want to be able to process the user's + // supplied childViews and then restore the original computed property + // at view initialization time. This happens in Ember.ContainerView's init + // method. + View.childViewsProperty = childViewsProperty; + + View.applyAttributeBindings = function(elem, name, value) { + var type = typeOf(value); + + // if this changes, also change the logic in ember-handlebars/lib/helpers/binding.js + if (name !== 'value' && (type === 'string' || (type === 'number' && !isNaN(value)))) { + if (value !== elem.attr(name)) { + elem.attr(name, value); + } + } else if (name === 'value' || type === 'boolean') { + if (isNone(value) || value === false) { + // `null`, `undefined` or `false` should remove attribute + elem.removeAttr(name); + // In IE8 `prop` couldn't remove attribute when name is `required`. + if (name === 'required') { + elem.removeProp(name); + } else { + elem.prop(name, ''); + } + } else if (value !== elem.prop(name)) { + // value should always be properties + elem.prop(name, value); + } + } else if (!value) { + elem.removeAttr(name); + } + }; + + __exports__["default"] = View; + }); +enifed("ember", + ["ember-metal","ember-runtime","ember-handlebars","ember-views","ember-routing","ember-routing-handlebars","ember-application","ember-extension-support"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__) { + "use strict"; + /* global navigator */ + // require the main entry points for each of these packages + // this is so that the global exports occur properly + + // do this to ensure that Ember.Test is defined properly on the global + // if it is present. + if (Ember.__loader.registry['ember-testing']) { + requireModule('ember-testing'); + } + + /** + Ember + + @module ember + */ + + Ember.deprecate('Usage of Ember is deprecated for Internet Explorer 6 and 7, support will be removed in the next major version.', !navigator.userAgent.match(/MSIE [67]/)); + }); +enifed("morph", + ["./morph/morph","./morph/dom-helper","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Morph = __dependency1__["default"]; + var Morph; + __exports__.Morph = Morph; + var DOMHelper = __dependency2__["default"]; + var DOMHelper; + __exports__.DOMHelper = DOMHelper; + }); +enifed("morph/dom-helper", + ["../morph/morph","./dom-helper/build-html-dom","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Morph = __dependency1__["default"]; + var buildHTMLDOM = __dependency2__.buildHTMLDOM; + var svgNamespace = __dependency2__.svgNamespace; + var svgHTMLIntegrationPoints = __dependency2__.svgHTMLIntegrationPoints; + + var deletesBlankTextNodes = (function(){ + var element = document.createElement('div'); + element.appendChild( document.createTextNode('') ); + var clonedElement = element.cloneNode(true); + return clonedElement.childNodes.length === 0; + })(); + + var ignoresCheckedAttribute = (function(){ + var element = document.createElement('input'); + element.setAttribute('checked', 'checked'); + var clonedElement = element.cloneNode(false); + return !clonedElement.checked; + })(); + + function isSVG(ns){ + return ns === svgNamespace; + } + + // This is not the namespace of the element, but of + // the elements inside that elements. + function interiorNamespace(element){ + if ( + element && + element.namespaceURI === svgNamespace && + !svgHTMLIntegrationPoints[element.tagName] + ) { + return svgNamespace; + } else { + return null; + } + } + + // The HTML spec allows for "omitted start tags". These tags are optional + // when their intended child is the first thing in the parent tag. For + // example, this is a tbody start tag: + // + //
    + // + // + // + // The tbody may be omitted, and the browser will accept and render: + // + //
    + // + // + // However, the omitted start tag will still be added to the DOM. Here + // we test the string and context to see if the browser is about to + // perform this cleanup. + // + // http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#optional-tags + // describes which tags are omittable. The spec for tbody and colgroup + // explains this behavior: + // + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-tbody-element + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-colgroup-element + // + + var omittedStartTagChildTest = /<([\w:]+)/; + function detectOmittedStartTag(string, contextualElement){ + // Omitted start tags are only inside table tags. + if (contextualElement.tagName === 'TABLE') { + var omittedStartTagChildMatch = omittedStartTagChildTest.exec(string); + if (omittedStartTagChildMatch) { + var omittedStartTagChild = omittedStartTagChildMatch[1]; + // It is already asserted that the contextual element is a table + // and not the proper start tag. Just see if a tag was omitted. + return omittedStartTagChild === 'tr' || + omittedStartTagChild === 'col'; + } + } + } + + function buildSVGDOM(html, dom){ + var div = dom.document.createElement('div'); + div.innerHTML = ''+html+''; + return div.firstChild.childNodes; + } + + /* + * A class wrapping DOM functions to address environment compatibility, + * namespaces, contextual elements for morph un-escaped content + * insertion. + * + * When entering a template, a DOMHelper should be passed: + * + * template(context, { hooks: hooks, dom: new DOMHelper() }); + * + * TODO: support foreignObject as a passed contextual element. It has + * a namespace (svg) that does not match its internal namespace + * (xhtml). + * + * @class DOMHelper + * @constructor + * @param {HTMLDocument} _document The document DOM methods are proxied to + */ + function DOMHelper(_document){ + this.document = _document || window.document; + this.namespace = null; + } + + var prototype = DOMHelper.prototype; + prototype.constructor = DOMHelper; + + prototype.insertBefore = function(element, childElement, referenceChild) { + return element.insertBefore(childElement, referenceChild); + }; + + prototype.appendChild = function(element, childElement) { + return element.appendChild(childElement); + }; + + prototype.appendText = function(element, text) { + return element.appendChild(this.document.createTextNode(text)); + }; + + prototype.setAttribute = function(element, name, value) { + element.setAttribute(name, value); + }; + + if (document.createElementNS) { + // Only opt into namespace detection if a contextualElement + // is passed. + prototype.createElement = function(tagName, contextualElement) { + var namespace = this.namespace; + if (contextualElement) { + if (tagName === 'svg') { + namespace = svgNamespace; + } else { + namespace = interiorNamespace(contextualElement); + } + } + if (namespace) { + return this.document.createElementNS(namespace, tagName); + } else { + return this.document.createElement(tagName); + } + }; + } else { + prototype.createElement = function(tagName) { + return this.document.createElement(tagName); + }; + } + + prototype.setNamespace = function(ns) { + this.namespace = ns; + }; + + prototype.detectNamespace = function(element) { + this.namespace = interiorNamespace(element); + }; + + prototype.createDocumentFragment = function(){ + return this.document.createDocumentFragment(); + }; + + prototype.createTextNode = function(text){ + return this.document.createTextNode(text); + }; + + prototype.repairClonedNode = function(element, blankChildTextNodes, isChecked){ + if (deletesBlankTextNodes && blankChildTextNodes.length > 0) { + for (var i=0, len=blankChildTextNodes.length;i]*)>", 'i'))[0]; + var endTag = ''; + + var wrappedHTML = [startTag, html, endTag]; + + var i = wrappingTags.length; + var wrappedDepth = 1 + i; + while(i--) { + wrappedHTML.unshift('<'+wrappingTags[i]+'>'); + wrappedHTML.push(''); + } + + var wrapper = document.createElement('div'); + scriptSafeInnerHTML(wrapper, wrappedHTML.join('')); + var element = wrapper; + while (wrappedDepth--) { + element = element.firstChild; + while (element && element.nodeType !== 1) { + element = element.nextSibling; + } + } + while (element && element.tagName !== tagName) { + element = element.nextSibling; + } + return element ? element.childNodes : []; + } + + var buildDOM; + if (needsShy) { + buildDOM = function buildDOM(html, contextualElement, dom){ + contextualElement = dom.cloneNode(contextualElement, false); + scriptSafeInnerHTML(contextualElement, html); + return contextualElement.childNodes; + }; + } else { + buildDOM = function buildDOM(html, contextualElement, dom){ + contextualElement = dom.cloneNode(contextualElement, false); + contextualElement.innerHTML = html; + return contextualElement.childNodes; + }; + } + + + var buildIESafeDOM; + if (tagNamesRequiringInnerHTMLFix || movesWhitespace) { + buildIESafeDOM = function buildIESafeDOM(html, contextualElement, dom) { + // Make a list of the leading text on script nodes. Include + // script tags without any whitespace for easier processing later. + var spacesBefore = []; + var spacesAfter = []; + html = html.replace(/(\s*)()(\s*)/g, function(match, tag, spaces) { + spacesAfter.push(spaces); + return tag; + }); + + // Fetch nodes + var nodes; + if (tagNamesRequiringInnerHTMLFix[contextualElement.tagName.toLowerCase()]) { + // buildDOMWithFix uses string wrappers for problematic innerHTML. + nodes = buildDOMWithFix(html, contextualElement); + } else { + nodes = buildDOM(html, contextualElement, dom); + } + + // Build a list of script tags, the nodes themselves will be + // mutated as we add test nodes. + var i, j, node, nodeScriptNodes; + var scriptNodes = []; + for (i=0;node=nodes[i];i++) { + if (node.nodeType !== 1) { + continue; + } + if (node.tagName === 'SCRIPT') { + scriptNodes.push(node); + } else { + nodeScriptNodes = node.getElementsByTagName('script'); + for (j=0;j 0) { + textNode = dom.document.createTextNode(spaceBefore); + scriptNode.parentNode.insertBefore(textNode, scriptNode); + } + + spaceAfter = spacesAfter[i]; + if (spaceAfter && spaceAfter.length > 0) { + textNode = dom.document.createTextNode(spaceAfter); + scriptNode.parentNode.insertBefore(textNode, scriptNode.nextSibling); + } + } + + return nodes; + }; + } else { + buildIESafeDOM = buildDOM; + } + + var buildHTMLDOM; + if (needsIntegrationPointFix) { + buildHTMLDOM = function buildHTMLDOM(html, contextualElement, dom){ + if (svgHTMLIntegrationPoints[contextualElement.tagName]) { + return buildIESafeDOM(html, document.createElement('div'), dom); + } else { + return buildIESafeDOM(html, contextualElement, dom); + } + }; + } else { + buildHTMLDOM = buildIESafeDOM; + } + + __exports__.buildHTMLDOM = buildHTMLDOM; + }); +enifed("morph/morph", + ["exports"], + function(__exports__) { + "use strict"; + var splice = Array.prototype.splice; + + function ensureStartEnd(start, end) { + if (start === null || end === null) { + throw new Error('a fragment parent must have boundary nodes in order to detect insertion'); + } + } + + function ensureContext(contextualElement) { + if (!contextualElement || contextualElement.nodeType !== 1) { + throw new Error('An element node must be provided for a contextualElement, you provided ' + + (contextualElement ? 'nodeType ' + contextualElement.nodeType : 'nothing')); + } + } + + // TODO: this is an internal API, this should be an assert + function Morph(parent, start, end, domHelper, contextualElement) { + if (parent.nodeType === 11) { + ensureStartEnd(start, end); + this.element = null; + } else { + this.element = parent; + } + this._parent = parent; + this.start = start; + this.end = end; + this.domHelper = domHelper; + ensureContext(contextualElement); + this.contextualElement = contextualElement; + this.reset(); + } + + Morph.prototype.reset = function() { + this.text = null; + this.owner = null; + this.morphs = null; + this.before = null; + this.after = null; + this.escaped = true; + }; + + Morph.prototype.parent = function () { + if (!this.element) { + var parent = this.start.parentNode; + if (this._parent !== parent) { + this.element = this._parent = parent; + } + } + return this._parent; + }; + + Morph.prototype.destroy = function () { + if (this.owner) { + this.owner.removeMorph(this); + } else { + clear(this.element || this.parent(), this.start, this.end); + } + }; + + Morph.prototype.removeMorph = function (morph) { + var morphs = this.morphs; + for (var i=0, l=morphs.length; i 0 ? morphs[index-1] : null; + var after = index < morphs.length ? morphs[index] : null; + var start = before === null ? this.start : (before.end === null ? parent.lastChild : before.end.previousSibling); + var end = after === null ? this.end : (after.start === null ? parent.firstChild : after.start.nextSibling); + var morph = new Morph(parent, start, end, this.domHelper, this.contextualElement); + + morph.owner = this; + morph._update(parent, node); + + if (before !== null) { + morph.before = before; + before.end = start.nextSibling; + before.after = morph; + } + + if (after !== null) { + morph.after = after; + after.before = morph; + after.start = end.previousSibling; + } + + this.morphs.splice(index, 0, morph); + return morph; + }; + + Morph.prototype.replace = function (index, removedLength, addedNodes) { + if (this.morphs === null) this.morphs = []; + var parent = this.element || this.parent(); + var morphs = this.morphs; + var before = index > 0 ? morphs[index-1] : null; + var after = index+removedLength < morphs.length ? morphs[index+removedLength] : null; + var start = before === null ? this.start : (before.end === null ? parent.lastChild : before.end.previousSibling); + var end = after === null ? this.end : (after.start === null ? parent.firstChild : after.start.nextSibling); + var addedLength = addedNodes === undefined ? 0 : addedNodes.length; + var args, i, current; + + if (removedLength > 0) { + clear(parent, start, end); + } + + if (addedLength === 0) { + if (before !== null) { + before.after = after; + before.end = end; + } + if (after !== null) { + after.before = before; + after.start = start; + } + morphs.splice(index, removedLength); + return; + } + + args = new Array(addedLength+2); + if (addedLength > 0) { + for (i=0; i " + n.nextStates.map(function(s) { return s.debug() }).join(" or ") + " )"; + }).join(", ") + } + END IF **/ + + // This is a somewhat naive strategy, but should work in a lot of cases + // A better strategy would properly resolve /posts/:id/new and /posts/edit/:id. + // + // This strategy generally prefers more static and less dynamic matching. + // Specifically, it + // + // * prefers fewer stars to more, then + // * prefers using stars for less of the match to more, then + // * prefers fewer dynamic segments to more, then + // * prefers more static segments to more + function sortSolutions(states) { + return states.sort(function(a, b) { + if (a.types.stars !== b.types.stars) { return a.types.stars - b.types.stars; } + + if (a.types.stars) { + if (a.types.statics !== b.types.statics) { return b.types.statics - a.types.statics; } + if (a.types.dynamics !== b.types.dynamics) { return b.types.dynamics - a.types.dynamics; } + } + + if (a.types.dynamics !== b.types.dynamics) { return a.types.dynamics - b.types.dynamics; } + if (a.types.statics !== b.types.statics) { return b.types.statics - a.types.statics; } + + return 0; + }); + } + + function recognizeChar(states, ch) { + var nextStates = []; + + for (var i=0, l=states.length; i 2 && key.slice(keyLength -2) === '[]') { + isArray = true; + key = key.slice(0, keyLength - 2); + if(!queryParams[key]) { + queryParams[key] = []; + } + } + value = pair[1] ? decodeURIComponent(pair[1]) : ''; + } + if (isArray) { + queryParams[key].push(value); + } else { + queryParams[key] = value; + } + } + return queryParams; + }, + + recognize: function(path) { + var states = [ this.rootState ], + pathLen, i, l, queryStart, queryParams = {}, + isSlashDropped = false; + + queryStart = path.indexOf('?'); + if (queryStart !== -1) { + var queryString = path.substr(queryStart + 1, path.length); + path = path.substr(0, queryStart); + queryParams = this.parseQueryString(queryString); + } + + path = decodeURI(path); + + // DEBUG GROUP path + + if (path.charAt(0) !== "/") { path = "/" + path; } + + pathLen = path.length; + if (pathLen > 1 && path.charAt(pathLen - 1) === "/") { + path = path.substr(0, pathLen - 1); + isSlashDropped = true; + } + + for (i=0, l=path.length; i= 0 && proceed; --i) { + var route = routes[i]; + recognizer.add(routes, { as: route.handler }); + proceed = route.path === '/' || route.path === '' || route.handler.slice(-6) === '.index'; + } + }); + }, + + hasRoute: function(route) { + return this.recognizer.hasRoute(route); + }, + + queryParamsTransition: function(changelist, wasTransitioning, oldState, newState) { + var router = this; + + fireQueryParamDidChange(this, newState, changelist); + + if (!wasTransitioning && this.activeTransition) { + // One of the handlers in queryParamsDidChange + // caused a transition. Just return that transition. + return this.activeTransition; + } else { + // Running queryParamsDidChange didn't change anything. + // Just update query params and be on our way. + + // We have to return a noop transition that will + // perform a URL update at the end. This gives + // the user the ability to set the url update + // method (default is replaceState). + var newTransition = new Transition(this); + newTransition.queryParamsOnly = true; + + oldState.queryParams = finalizeQueryParamChange(this, newState.handlerInfos, newState.queryParams, newTransition); + + newTransition.promise = newTransition.promise.then(function(result) { + updateURL(newTransition, oldState, true); + if (router.didTransition) { + router.didTransition(router.currentHandlerInfos); + } + return result; + }, null, promiseLabel("Transition complete")); + return newTransition; + } + }, + + // NOTE: this doesn't really belong here, but here + // it shall remain until our ES6 transpiler can + // handle cyclical deps. + transitionByIntent: function(intent, isIntermediate) { + try { + return getTransitionByIntent.apply(this, arguments); + } catch(e) { + return new Transition(this, intent, null, e); + } + }, + + /** + Clears the current and target route handlers and triggers exit + on each of them starting at the leaf and traversing up through + its ancestors. + */ + reset: function() { + if (this.state) { + forEach(this.state.handlerInfos.slice().reverse(), function(handlerInfo) { + var handler = handlerInfo.handler; + callHook(handler, 'exit'); + }); + } + + this.state = new TransitionState(); + this.currentHandlerInfos = null; + }, + + activeTransition: null, + + /** + var handler = handlerInfo.handler; + The entry point for handling a change to the URL (usually + via the back and forward button). + + Returns an Array of handlers and the parameters associated + with those parameters. + + @param {String} url a URL to process + + @return {Array} an Array of `[handler, parameter]` tuples + */ + handleURL: function(url) { + // Perform a URL-based transition, but don't change + // the URL afterward, since it already happened. + var args = slice.call(arguments); + if (url.charAt(0) !== '/') { args[0] = '/' + url; } + + return doTransition(this, args).method(null); + }, + + /** + Hook point for updating the URL. + + @param {String} url a URL to update to + */ + updateURL: function() { + throw new Error("updateURL is not implemented"); + }, + + /** + Hook point for replacing the current URL, i.e. with replaceState + + By default this behaves the same as `updateURL` + + @param {String} url a URL to update to + */ + replaceURL: function(url) { + this.updateURL(url); + }, + + /** + Transition into the specified named route. + + If necessary, trigger the exit callback on any handlers + that are no longer represented by the target route. + + @param {String} name the name of the route + */ + transitionTo: function(name) { + return doTransition(this, arguments); + }, + + intermediateTransitionTo: function(name) { + return doTransition(this, arguments, true); + }, + + refresh: function(pivotHandler) { + var state = this.activeTransition ? this.activeTransition.state : this.state; + var handlerInfos = state.handlerInfos; + var params = {}; + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var handlerInfo = handlerInfos[i]; + params[handlerInfo.name] = handlerInfo.params || {}; + } + + log(this, "Starting a refresh transition"); + var intent = new NamedTransitionIntent({ + name: handlerInfos[handlerInfos.length - 1].name, + pivotHandler: pivotHandler || handlerInfos[0].handler, + contexts: [], // TODO collect contexts...? + queryParams: this._changedQueryParams || state.queryParams || {} + }); + + return this.transitionByIntent(intent, false); + }, + + /** + Identical to `transitionTo` except that the current URL will be replaced + if possible. + + This method is intended primarily for use with `replaceState`. + + @param {String} name the name of the route + */ + replaceWith: function(name) { + return doTransition(this, arguments).method('replace'); + }, + + /** + Take a named route and context objects and generate a + URL. + + @param {String} name the name of the route to generate + a URL for + @param {...Object} objects a list of objects to serialize + + @return {String} a URL + */ + generate: function(handlerName) { + + var partitionedArgs = extractQueryParams(slice.call(arguments, 1)), + suppliedParams = partitionedArgs[0], + queryParams = partitionedArgs[1]; + + // Construct a TransitionIntent with the provided params + // and apply it to the present state of the router. + var intent = new NamedTransitionIntent({ name: handlerName, contexts: suppliedParams }); + var state = intent.applyToState(this.state, this.recognizer, this.getHandler); + var params = {}; + + for (var i = 0, len = state.handlerInfos.length; i < len; ++i) { + var handlerInfo = state.handlerInfos[i]; + var handlerParams = handlerInfo.serialize(); + merge(params, handlerParams); + } + params.queryParams = queryParams; + + return this.recognizer.generate(handlerName, params); + }, + + applyIntent: function(handlerName, contexts) { + var intent = new NamedTransitionIntent({ + name: handlerName, + contexts: contexts + }); + + var state = this.activeTransition && this.activeTransition.state || this.state; + return intent.applyToState(state, this.recognizer, this.getHandler); + }, + + isActiveIntent: function(handlerName, contexts, queryParams) { + var targetHandlerInfos = this.state.handlerInfos, + found = false, names, object, handlerInfo, handlerObj, i, len; + + if (!targetHandlerInfos.length) { return false; } + + var targetHandler = targetHandlerInfos[targetHandlerInfos.length - 1].name; + var recogHandlers = this.recognizer.handlersFor(targetHandler); + + var index = 0; + for (len = recogHandlers.length; index < len; ++index) { + handlerInfo = targetHandlerInfos[index]; + if (handlerInfo.name === handlerName) { break; } + } + + if (index === recogHandlers.length) { + // The provided route name isn't even in the route hierarchy. + return false; + } + + var state = new TransitionState(); + state.handlerInfos = targetHandlerInfos.slice(0, index + 1); + recogHandlers = recogHandlers.slice(0, index + 1); + + var intent = new NamedTransitionIntent({ + name: targetHandler, + contexts: contexts + }); + + var newState = intent.applyToHandlers(state, recogHandlers, this.getHandler, targetHandler, true, true); + + var handlersEqual = handlerInfosEqual(newState.handlerInfos, state.handlerInfos); + if (!queryParams || !handlersEqual) { + return handlersEqual; + } + + // Get a hash of QPs that will still be active on new route + var activeQPsOnNewHandler = {}; + merge(activeQPsOnNewHandler, queryParams); + + var activeQueryParams = this.state.queryParams; + for (var key in activeQueryParams) { + if (activeQueryParams.hasOwnProperty(key) && + activeQPsOnNewHandler.hasOwnProperty(key)) { + activeQPsOnNewHandler[key] = activeQueryParams[key]; + } + } + + return handlersEqual && !getChangelist(activeQPsOnNewHandler, queryParams); + }, + + isActive: function(handlerName) { + var partitionedArgs = extractQueryParams(slice.call(arguments, 1)); + return this.isActiveIntent(handlerName, partitionedArgs[0], partitionedArgs[1]); + }, + + trigger: function(name) { + var args = slice.call(arguments); + trigger(this, this.currentHandlerInfos, false, args); + }, + + /** + Hook point for logging transition status updates. + + @param {String} message The message to log. + */ + log: null, + + _willChangeContextEvent: 'willChangeContext', + _triggerWillChangeContext: function(handlerInfos, newTransition) { + trigger(this, handlerInfos, true, [this._willChangeContextEvent, newTransition]); + }, + + _triggerWillLeave: function(handlerInfos, newTransition, leavingChecker) { + trigger(this, handlerInfos, true, ['willLeave', newTransition, leavingChecker]); + } + }; + + /** + @private + + Fires queryParamsDidChange event + */ + function fireQueryParamDidChange(router, newState, queryParamChangelist) { + // If queryParams changed trigger event + if (queryParamChangelist) { + + // This is a little hacky but we need some way of storing + // changed query params given that no activeTransition + // is guaranteed to have occurred. + router._changedQueryParams = queryParamChangelist.all; + trigger(router, newState.handlerInfos, true, ['queryParamsDidChange', queryParamChangelist.changed, queryParamChangelist.all, queryParamChangelist.removed]); + router._changedQueryParams = null; + } + } + + /** + @private + + Takes an Array of `HandlerInfo`s, figures out which ones are + exiting, entering, or changing contexts, and calls the + proper handler hooks. + + For example, consider the following tree of handlers. Each handler is + followed by the URL segment it handles. + + ``` + |~index ("/") + | |~posts ("/posts") + | | |-showPost ("/:id") + | | |-newPost ("/new") + | | |-editPost ("/edit") + | |~about ("/about/:id") + ``` + + Consider the following transitions: + + 1. A URL transition to `/posts/1`. + 1. Triggers the `*model` callbacks on the + `index`, `posts`, and `showPost` handlers + 2. Triggers the `enter` callback on the same + 3. Triggers the `setup` callback on the same + 2. A direct transition to `newPost` + 1. Triggers the `exit` callback on `showPost` + 2. Triggers the `enter` callback on `newPost` + 3. Triggers the `setup` callback on `newPost` + 3. A direct transition to `about` with a specified + context object + 1. Triggers the `exit` callback on `newPost` + and `posts` + 2. Triggers the `serialize` callback on `about` + 3. Triggers the `enter` callback on `about` + 4. Triggers the `setup` callback on `about` + + @param {Router} transition + @param {TransitionState} newState + */ + function setupContexts(router, newState, transition) { + var partition = partitionHandlers(router.state, newState); + + forEach(partition.exited, function(handlerInfo) { + var handler = handlerInfo.handler; + delete handler.context; + + callHook(handler, 'reset', true, transition); + callHook(handler, 'exit', transition); + }); + + var oldState = router.oldState = router.state; + router.state = newState; + var currentHandlerInfos = router.currentHandlerInfos = partition.unchanged.slice(); + + try { + forEach(partition.reset, function(handlerInfo) { + var handler = handlerInfo.handler; + callHook(handler, 'reset', false, transition); + }); + + forEach(partition.updatedContext, function(handlerInfo) { + return handlerEnteredOrUpdated(currentHandlerInfos, handlerInfo, false, transition); + }); + + forEach(partition.entered, function(handlerInfo) { + return handlerEnteredOrUpdated(currentHandlerInfos, handlerInfo, true, transition); + }); + } catch(e) { + router.state = oldState; + router.currentHandlerInfos = oldState.handlerInfos; + throw e; + } + + router.state.queryParams = finalizeQueryParamChange(router, currentHandlerInfos, newState.queryParams, transition); + } + + + /** + @private + + Helper method used by setupContexts. Handles errors or redirects + that may happen in enter/setup. + */ + function handlerEnteredOrUpdated(currentHandlerInfos, handlerInfo, enter, transition) { + + var handler = handlerInfo.handler, + context = handlerInfo.context; + + if (enter) { + callHook(handler, 'enter', transition); + } + if (transition && transition.isAborted) { + throw new TransitionAborted(); + } + + handler.context = context; + callHook(handler, 'contextDidChange'); + + callHook(handler, 'setup', context, transition); + if (transition && transition.isAborted) { + throw new TransitionAborted(); + } + + currentHandlerInfos.push(handlerInfo); + + return true; + } + + + /** + @private + + This function is called when transitioning from one URL to + another to determine which handlers are no longer active, + which handlers are newly active, and which handlers remain + active but have their context changed. + + Take a list of old handlers and new handlers and partition + them into four buckets: + + * unchanged: the handler was active in both the old and + new URL, and its context remains the same + * updated context: the handler was active in both the + old and new URL, but its context changed. The handler's + `setup` method, if any, will be called with the new + context. + * exited: the handler was active in the old URL, but is + no longer active. + * entered: the handler was not active in the old URL, but + is now active. + + The PartitionedHandlers structure has four fields: + + * `updatedContext`: a list of `HandlerInfo` objects that + represent handlers that remain active but have a changed + context + * `entered`: a list of `HandlerInfo` objects that represent + handlers that are newly active + * `exited`: a list of `HandlerInfo` objects that are no + longer active. + * `unchanged`: a list of `HanderInfo` objects that remain active. + + @param {Array[HandlerInfo]} oldHandlers a list of the handler + information for the previous URL (or `[]` if this is the + first handled transition) + @param {Array[HandlerInfo]} newHandlers a list of the handler + information for the new URL + + @return {Partition} + */ + function partitionHandlers(oldState, newState) { + var oldHandlers = oldState.handlerInfos; + var newHandlers = newState.handlerInfos; + + var handlers = { + updatedContext: [], + exited: [], + entered: [], + unchanged: [] + }; + + var handlerChanged, contextChanged = false, i, l; + + for (i=0, l=newHandlers.length; i= 0; --i) { + var handlerInfo = handlerInfos[i]; + merge(params, handlerInfo.params); + if (handlerInfo.handler.inaccessibleByURL) { + urlMethod = null; + } + } + + if (urlMethod) { + params.queryParams = transition._visibleQueryParams || state.queryParams; + var url = router.recognizer.generate(handlerName, params); + + if (urlMethod === 'replace') { + router.replaceURL(url); + } else { + router.updateURL(url); + } + } + } + + /** + @private + + Updates the URL (if necessary) and calls `setupContexts` + to update the router's array of `currentHandlerInfos`. + */ + function finalizeTransition(transition, newState) { + + try { + log(transition.router, transition.sequence, "Resolved all models on destination route; finalizing transition."); + + var router = transition.router, + handlerInfos = newState.handlerInfos, + seq = transition.sequence; + + // Run all the necessary enter/setup/exit hooks + setupContexts(router, newState, transition); + + // Check if a redirect occurred in enter/setup + if (transition.isAborted) { + // TODO: cleaner way? distinguish b/w targetHandlerInfos? + router.state.handlerInfos = router.currentHandlerInfos; + return Promise.reject(logAbort(transition)); + } + + updateURL(transition, newState, transition.intent.url); + + transition.isActive = false; + router.activeTransition = null; + + trigger(router, router.currentHandlerInfos, true, ['didTransition']); + + if (router.didTransition) { + router.didTransition(router.currentHandlerInfos); + } + + log(router, transition.sequence, "TRANSITION COMPLETE."); + + // Resolve with the final handler. + return handlerInfos[handlerInfos.length - 1].handler; + } catch(e) { + if (!((e instanceof TransitionAborted))) { + //var erroneousHandler = handlerInfos.pop(); + var infos = transition.state.handlerInfos; + transition.trigger(true, 'error', e, transition, infos[infos.length-1].handler); + transition.abort(); + } + + throw e; + } + } + + /** + @private + + Begins and returns a Transition based on the provided + arguments. Accepts arguments in the form of both URL + transitions and named transitions. + + @param {Router} router + @param {Array[Object]} args arguments passed to transitionTo, + replaceWith, or handleURL + */ + function doTransition(router, args, isIntermediate) { + // Normalize blank transitions to root URL transitions. + var name = args[0] || '/'; + + var lastArg = args[args.length-1]; + var queryParams = {}; + if (lastArg && lastArg.hasOwnProperty('queryParams')) { + queryParams = pop.call(args).queryParams; + } + + var intent; + if (args.length === 0) { + + log(router, "Updating query params"); + + // A query param update is really just a transition + // into the route you're already on. + var handlerInfos = router.state.handlerInfos; + intent = new NamedTransitionIntent({ + name: handlerInfos[handlerInfos.length - 1].name, + contexts: [], + queryParams: queryParams + }); + + } else if (name.charAt(0) === '/') { + + log(router, "Attempting URL transition to " + name); + intent = new URLTransitionIntent({ url: name }); + + } else { + + log(router, "Attempting transition to " + name); + intent = new NamedTransitionIntent({ + name: args[0], + contexts: slice.call(args, 1), + queryParams: queryParams + }); + } + + return router.transitionByIntent(intent, isIntermediate); + } + + function handlerInfosEqual(handlerInfos, otherHandlerInfos) { + if (handlerInfos.length !== otherHandlerInfos.length) { + return false; + } + + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + if (handlerInfos[i] !== otherHandlerInfos[i]) { + return false; + } + } + return true; + } + + function finalizeQueryParamChange(router, resolvedHandlers, newQueryParams, transition) { + // We fire a finalizeQueryParamChange event which + // gives the new route hierarchy a chance to tell + // us which query params it's consuming and what + // their final values are. If a query param is + // no longer consumed in the final route hierarchy, + // its serialized segment will be removed + // from the URL. + + for (var k in newQueryParams) { + if (newQueryParams.hasOwnProperty(k) && + newQueryParams[k] === null) { + delete newQueryParams[k]; + } + } + + var finalQueryParamsArray = []; + trigger(router, resolvedHandlers, true, ['finalizeQueryParamChange', newQueryParams, finalQueryParamsArray, transition]); + + if (transition) { + transition._visibleQueryParams = {}; + } + + var finalQueryParams = {}; + for (var i = 0, len = finalQueryParamsArray.length; i < len; ++i) { + var qp = finalQueryParamsArray[i]; + finalQueryParams[qp.key] = qp.value; + if (transition && qp.visible !== false) { + transition._visibleQueryParams[qp.key] = qp.value; + } + } + return finalQueryParams; + } + + function notifyExistingHandlers(router, newState, newTransition) { + var oldHandlers = router.state.handlerInfos, + changing = [], + leavingIndex = null, + leaving, leavingChecker, i, oldHandlerLen, oldHandler, newHandler; + + oldHandlerLen = oldHandlers.length; + for (i = 0; i < oldHandlerLen; i++) { + oldHandler = oldHandlers[i]; + newHandler = newState.handlerInfos[i]; + + if (!newHandler || oldHandler.name !== newHandler.name) { + leavingIndex = i; + break; + } + + if (!newHandler.isResolved) { + changing.push(oldHandler); + } + } + + if (leavingIndex !== null) { + leaving = oldHandlers.slice(leavingIndex, oldHandlerLen); + leavingChecker = function(name) { + for (var h = 0, len = leaving.length; h < len; h++) { + if (leaving[h].name === name) { + return true; + } + } + return false; + }; + + router._triggerWillLeave(leaving, newTransition, leavingChecker); + } + + if (changing.length > 0) { + router._triggerWillChangeContext(changing, newTransition); + } + + trigger(router, oldHandlers, true, ['willTransition', newTransition]); + } + + __exports__["default"] = Router; + }); +enifed("router/transition-intent", + ["./utils","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var merge = __dependency1__.merge; + + function TransitionIntent(props) { + this.initialize(props); + + // TODO: wat + this.data = this.data || {}; + } + + TransitionIntent.prototype = { + initialize: null, + applyToState: null + }; + + __exports__["default"] = TransitionIntent; + }); +enifed("router/transition-intent/named-transition-intent", + ["../transition-intent","../transition-state","../handler-info/factory","../utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var TransitionIntent = __dependency1__["default"]; + var TransitionState = __dependency2__["default"]; + var handlerInfoFactory = __dependency3__["default"]; + var isParam = __dependency4__.isParam; + var extractQueryParams = __dependency4__.extractQueryParams; + var merge = __dependency4__.merge; + var subclass = __dependency4__.subclass; + + __exports__["default"] = subclass(TransitionIntent, { + name: null, + pivotHandler: null, + contexts: null, + queryParams: null, + + initialize: function(props) { + this.name = props.name; + this.pivotHandler = props.pivotHandler; + this.contexts = props.contexts || []; + this.queryParams = props.queryParams; + }, + + applyToState: function(oldState, recognizer, getHandler, isIntermediate) { + + var partitionedArgs = extractQueryParams([this.name].concat(this.contexts)), + pureArgs = partitionedArgs[0], + queryParams = partitionedArgs[1], + handlers = recognizer.handlersFor(pureArgs[0]); + + var targetRouteName = handlers[handlers.length-1].handler; + + return this.applyToHandlers(oldState, handlers, getHandler, targetRouteName, isIntermediate); + }, + + applyToHandlers: function(oldState, handlers, getHandler, targetRouteName, isIntermediate, checkingIfActive) { + + var i, len; + var newState = new TransitionState(); + var objects = this.contexts.slice(0); + + var invalidateIndex = handlers.length; + + // Pivot handlers are provided for refresh transitions + if (this.pivotHandler) { + for (i = 0, len = handlers.length; i < len; ++i) { + if (getHandler(handlers[i].handler) === this.pivotHandler) { + invalidateIndex = i; + break; + } + } + } + + var pivotHandlerFound = !this.pivotHandler; + + for (i = handlers.length - 1; i >= 0; --i) { + var result = handlers[i]; + var name = result.handler; + var handler = getHandler(name); + + var oldHandlerInfo = oldState.handlerInfos[i]; + var newHandlerInfo = null; + + if (result.names.length > 0) { + if (i >= invalidateIndex) { + newHandlerInfo = this.createParamHandlerInfo(name, handler, result.names, objects, oldHandlerInfo); + } else { + newHandlerInfo = this.getHandlerInfoForDynamicSegment(name, handler, result.names, objects, oldHandlerInfo, targetRouteName, i); + } + } else { + // This route has no dynamic segment. + // Therefore treat as a param-based handlerInfo + // with empty params. This will cause the `model` + // hook to be called with empty params, which is desirable. + newHandlerInfo = this.createParamHandlerInfo(name, handler, result.names, objects, oldHandlerInfo); + } + + if (checkingIfActive) { + // If we're performing an isActive check, we want to + // serialize URL params with the provided context, but + // ignore mismatches between old and new context. + newHandlerInfo = newHandlerInfo.becomeResolved(null, newHandlerInfo.context); + var oldContext = oldHandlerInfo && oldHandlerInfo.context; + if (result.names.length > 0 && newHandlerInfo.context === oldContext) { + // If contexts match in isActive test, assume params also match. + // This allows for flexibility in not requiring that every last + // handler provide a `serialize` method + newHandlerInfo.params = oldHandlerInfo && oldHandlerInfo.params; + } + newHandlerInfo.context = oldContext; + } + + var handlerToUse = oldHandlerInfo; + if (i >= invalidateIndex || newHandlerInfo.shouldSupercede(oldHandlerInfo)) { + invalidateIndex = Math.min(i, invalidateIndex); + handlerToUse = newHandlerInfo; + } + + if (isIntermediate && !checkingIfActive) { + handlerToUse = handlerToUse.becomeResolved(null, handlerToUse.context); + } + + newState.handlerInfos.unshift(handlerToUse); + } + + if (objects.length > 0) { + throw new Error("More context objects were passed than there are dynamic segments for the route: " + targetRouteName); + } + + if (!isIntermediate) { + this.invalidateChildren(newState.handlerInfos, invalidateIndex); + } + + merge(newState.queryParams, this.queryParams || {}); + + return newState; + }, + + invalidateChildren: function(handlerInfos, invalidateIndex) { + for (var i = invalidateIndex, l = handlerInfos.length; i < l; ++i) { + var handlerInfo = handlerInfos[i]; + handlerInfos[i] = handlerInfos[i].getUnresolved(); + } + }, + + getHandlerInfoForDynamicSegment: function(name, handler, names, objects, oldHandlerInfo, targetRouteName, i) { + + var numNames = names.length; + var objectToUse; + if (objects.length > 0) { + + // Use the objects provided for this transition. + objectToUse = objects[objects.length - 1]; + if (isParam(objectToUse)) { + return this.createParamHandlerInfo(name, handler, names, objects, oldHandlerInfo); + } else { + objects.pop(); + } + } else if (oldHandlerInfo && oldHandlerInfo.name === name) { + // Reuse the matching oldHandlerInfo + return oldHandlerInfo; + } else { + if (this.preTransitionState) { + var preTransitionHandlerInfo = this.preTransitionState.handlerInfos[i]; + objectToUse = preTransitionHandlerInfo && preTransitionHandlerInfo.context; + } else { + // Ideally we should throw this error to provide maximal + // information to the user that not enough context objects + // were provided, but this proves too cumbersome in Ember + // in cases where inner template helpers are evaluated + // before parent helpers un-render, in which cases this + // error somewhat prematurely fires. + //throw new Error("Not enough context objects were provided to complete a transition to " + targetRouteName + ". Specifically, the " + name + " route needs an object that can be serialized into its dynamic URL segments [" + names.join(', ') + "]"); + return oldHandlerInfo; + } + } + + return handlerInfoFactory('object', { + name: name, + handler: handler, + context: objectToUse, + names: names + }); + }, + + createParamHandlerInfo: function(name, handler, names, objects, oldHandlerInfo) { + var params = {}; + + // Soak up all the provided string/numbers + var numNames = names.length; + while (numNames--) { + + // Only use old params if the names match with the new handler + var oldParams = (oldHandlerInfo && name === oldHandlerInfo.name && oldHandlerInfo.params) || {}; + + var peek = objects[objects.length - 1]; + var paramName = names[numNames]; + if (isParam(peek)) { + params[paramName] = "" + objects.pop(); + } else { + // If we're here, this means only some of the params + // were string/number params, so try and use a param + // value from a previous handler. + if (oldParams.hasOwnProperty(paramName)) { + params[paramName] = oldParams[paramName]; + } else { + throw new Error("You didn't provide enough string/numeric parameters to satisfy all of the dynamic segments for route " + name); + } + } + } + + return handlerInfoFactory('param', { + name: name, + handler: handler, + params: params + }); + } + }); + }); +enifed("router/transition-intent/url-transition-intent", + ["../transition-intent","../transition-state","../handler-info/factory","../utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var TransitionIntent = __dependency1__["default"]; + var TransitionState = __dependency2__["default"]; + var handlerInfoFactory = __dependency3__["default"]; + var oCreate = __dependency4__.oCreate; + var merge = __dependency4__.merge; + var subclass = __dependency4__.subclass; + + __exports__["default"] = subclass(TransitionIntent, { + url: null, + + initialize: function(props) { + this.url = props.url; + }, + + applyToState: function(oldState, recognizer, getHandler) { + var newState = new TransitionState(); + + var results = recognizer.recognize(this.url), + queryParams = {}, + i, len; + + if (!results) { + throw new UnrecognizedURLError(this.url); + } + + var statesDiffer = false; + + for (i = 0, len = results.length; i < len; ++i) { + var result = results[i]; + var name = result.handler; + var handler = getHandler(name); + + if (handler.inaccessibleByURL) { + throw new UnrecognizedURLError(this.url); + } + + var newHandlerInfo = handlerInfoFactory('param', { + name: name, + handler: handler, + params: result.params + }); + + var oldHandlerInfo = oldState.handlerInfos[i]; + if (statesDiffer || newHandlerInfo.shouldSupercede(oldHandlerInfo)) { + statesDiffer = true; + newState.handlerInfos[i] = newHandlerInfo; + } else { + newState.handlerInfos[i] = oldHandlerInfo; + } + } + + merge(newState.queryParams, results.queryParams); + + return newState; + } + }); + + /** + Promise reject reasons passed to promise rejection + handlers for failed transitions. + */ + function UnrecognizedURLError(message) { + this.message = (message || "UnrecognizedURLError"); + this.name = "UnrecognizedURLError"; + } + }); +enifed("router/transition-state", + ["./handler-info","./utils","rsvp/promise","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var ResolvedHandlerInfo = __dependency1__.ResolvedHandlerInfo; + var forEach = __dependency2__.forEach; + var promiseLabel = __dependency2__.promiseLabel; + var callHook = __dependency2__.callHook; + var Promise = __dependency3__["default"]; + + function TransitionState(other) { + this.handlerInfos = []; + this.queryParams = {}; + this.params = {}; + } + + TransitionState.prototype = { + handlerInfos: null, + queryParams: null, + params: null, + + promiseLabel: function(label) { + var targetName = ''; + forEach(this.handlerInfos, function(handlerInfo) { + if (targetName !== '') { + targetName += '.'; + } + targetName += handlerInfo.name; + }); + return promiseLabel("'" + targetName + "': " + label); + }, + + resolve: function(shouldContinue, payload) { + var self = this; + // First, calculate params for this state. This is useful + // information to provide to the various route hooks. + var params = this.params; + forEach(this.handlerInfos, function(handlerInfo) { + params[handlerInfo.name] = handlerInfo.params || {}; + }); + + payload = payload || {}; + payload.resolveIndex = 0; + + var currentState = this; + var wasAborted = false; + + // The prelude RSVP.resolve() asyncs us into the promise land. + return Promise.resolve(null, this.promiseLabel("Start transition")) + .then(resolveOneHandlerInfo, null, this.promiseLabel('Resolve handler'))['catch'](handleError, this.promiseLabel('Handle error')); + + function innerShouldContinue() { + return Promise.resolve(shouldContinue(), currentState.promiseLabel("Check if should continue"))['catch'](function(reason) { + // We distinguish between errors that occurred + // during resolution (e.g. beforeModel/model/afterModel), + // and aborts due to a rejecting promise from shouldContinue(). + wasAborted = true; + return Promise.reject(reason); + }, currentState.promiseLabel("Handle abort")); + } + + function handleError(error) { + // This is the only possible + // reject value of TransitionState#resolve + var handlerInfos = currentState.handlerInfos; + var errorHandlerIndex = payload.resolveIndex >= handlerInfos.length ? + handlerInfos.length - 1 : payload.resolveIndex; + return Promise.reject({ + error: error, + handlerWithError: currentState.handlerInfos[errorHandlerIndex].handler, + wasAborted: wasAborted, + state: currentState + }); + } + + function proceed(resolvedHandlerInfo) { + var wasAlreadyResolved = currentState.handlerInfos[payload.resolveIndex].isResolved; + + // Swap the previously unresolved handlerInfo with + // the resolved handlerInfo + currentState.handlerInfos[payload.resolveIndex++] = resolvedHandlerInfo; + + if (!wasAlreadyResolved) { + // Call the redirect hook. The reason we call it here + // vs. afterModel is so that redirects into child + // routes don't re-run the model hooks for this + // already-resolved route. + var handler = resolvedHandlerInfo.handler; + callHook(handler, 'redirect', resolvedHandlerInfo.context, payload); + } + + // Proceed after ensuring that the redirect hook + // didn't abort this transition by transitioning elsewhere. + return innerShouldContinue().then(resolveOneHandlerInfo, null, currentState.promiseLabel('Resolve handler')); + } + + function resolveOneHandlerInfo() { + if (payload.resolveIndex === currentState.handlerInfos.length) { + // This is is the only possible + // fulfill value of TransitionState#resolve + return { + error: null, + state: currentState + }; + } + + var handlerInfo = currentState.handlerInfos[payload.resolveIndex]; + + return handlerInfo.resolve(innerShouldContinue, payload) + .then(proceed, null, currentState.promiseLabel('Proceed')); + } + } + }; + + __exports__["default"] = TransitionState; + }); +enifed("router/transition", + ["rsvp/promise","./handler-info","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var ResolvedHandlerInfo = __dependency2__.ResolvedHandlerInfo; + var trigger = __dependency3__.trigger; + var slice = __dependency3__.slice; + var log = __dependency3__.log; + var promiseLabel = __dependency3__.promiseLabel; + + /** + @private + + A Transition is a thennable (a promise-like object) that represents + an attempt to transition to another route. It can be aborted, either + explicitly via `abort` or by attempting another transition while a + previous one is still underway. An aborted transition can also + be `retry()`d later. + */ + function Transition(router, intent, state, error) { + var transition = this; + this.state = state || router.state; + this.intent = intent; + this.router = router; + this.data = this.intent && this.intent.data || {}; + this.resolvedModels = {}; + this.queryParams = {}; + + if (error) { + this.promise = Promise.reject(error); + return; + } + + if (state) { + this.params = state.params; + this.queryParams = state.queryParams; + this.handlerInfos = state.handlerInfos; + + var len = state.handlerInfos.length; + if (len) { + this.targetName = state.handlerInfos[len-1].name; + } + + for (var i = 0; i < len; ++i) { + var handlerInfo = state.handlerInfos[i]; + + // TODO: this all seems hacky + if (!handlerInfo.isResolved) { break; } + this.pivotHandler = handlerInfo.handler; + } + + this.sequence = Transition.currentSequence++; + this.promise = state.resolve(checkForAbort, this)['catch'](function(result) { + if (result.wasAborted || transition.isAborted) { + return Promise.reject(logAbort(transition)); + } else { + transition.trigger('error', result.error, transition, result.handlerWithError); + transition.abort(); + return Promise.reject(result.error); + } + }, promiseLabel('Handle Abort')); + } else { + this.promise = Promise.resolve(this.state); + this.params = {}; + } + + function checkForAbort() { + if (transition.isAborted) { + return Promise.reject(undefined, promiseLabel("Transition aborted - reject")); + } + } + } + + Transition.currentSequence = 0; + + Transition.prototype = { + targetName: null, + urlMethod: 'update', + intent: null, + params: null, + pivotHandler: null, + resolveIndex: 0, + handlerInfos: null, + resolvedModels: null, + isActive: true, + state: null, + queryParamsOnly: false, + + isTransition: true, + + isExiting: function(handler) { + var handlerInfos = this.handlerInfos; + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var handlerInfo = handlerInfos[i]; + if (handlerInfo.name === handler || handlerInfo.handler === handler) { + return false; + } + } + return true; + }, + + /** + @public + + The Transition's internal promise. Calling `.then` on this property + is that same as calling `.then` on the Transition object itself, but + this property is exposed for when you want to pass around a + Transition's promise, but not the Transition object itself, since + Transition object can be externally `abort`ed, while the promise + cannot. + */ + promise: null, + + /** + @public + + Custom state can be stored on a Transition's `data` object. + This can be useful for decorating a Transition within an earlier + hook and shared with a later hook. Properties set on `data` will + be copied to new transitions generated by calling `retry` on this + transition. + */ + data: null, + + /** + @public + + A standard promise hook that resolves if the transition + succeeds and rejects if it fails/redirects/aborts. + + Forwards to the internal `promise` property which you can + use in situations where you want to pass around a thennable, + but not the Transition itself. + + @param {Function} onFulfilled + @param {Function} onRejected + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + then: function(onFulfilled, onRejected, label) { + return this.promise.then(onFulfilled, onRejected, label); + }, + + /** + @public + + Forwards to the internal `promise` property which you can + use in situations where you want to pass around a thennable, + but not the Transition itself. + + @method catch + @param {Function} onRejection + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + "catch": function(onRejection, label) { + return this.promise["catch"](onRejection, label); + }, + + /** + @public + + Forwards to the internal `promise` property which you can + use in situations where you want to pass around a thennable, + but not the Transition itself. + + @method finally + @param {Function} callback + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + "finally": function(callback, label) { + return this.promise["finally"](callback, label); + }, + + /** + @public + + Aborts the Transition. Note you can also implicitly abort a transition + by initiating another transition while a previous one is underway. + */ + abort: function() { + if (this.isAborted) { return this; } + log(this.router, this.sequence, this.targetName + ": transition was aborted"); + this.intent.preTransitionState = this.router.state; + this.isAborted = true; + this.isActive = false; + this.router.activeTransition = null; + return this; + }, + + /** + @public + + Retries a previously-aborted transition (making sure to abort the + transition if it's still active). Returns a new transition that + represents the new attempt to transition. + */ + retry: function() { + // TODO: add tests for merged state retry()s + this.abort(); + return this.router.transitionByIntent(this.intent, false); + }, + + /** + @public + + Sets the URL-changing method to be employed at the end of a + successful transition. By default, a new Transition will just + use `updateURL`, but passing 'replace' to this method will + cause the URL to update using 'replaceWith' instead. Omitting + a parameter will disable the URL change, allowing for transitions + that don't update the URL at completion (this is also used for + handleURL, since the URL has already changed before the + transition took place). + + @param {String} method the type of URL-changing method to use + at the end of a transition. Accepted values are 'replace', + falsy values, or any other non-falsy value (which is + interpreted as an updateURL transition). + + @return {Transition} this transition + */ + method: function(method) { + this.urlMethod = method; + return this; + }, + + /** + @public + + Fires an event on the current list of resolved/resolving + handlers within this transition. Useful for firing events + on route hierarchies that haven't fully been entered yet. + + Note: This method is also aliased as `send` + + @param {Boolean} [ignoreFailure=false] a boolean specifying whether unhandled events throw an error + @param {String} name the name of the event to fire + */ + trigger: function (ignoreFailure) { + var args = slice.call(arguments); + if (typeof ignoreFailure === 'boolean') { + args.shift(); + } else { + // Throw errors on unhandled trigger events by default + ignoreFailure = false; + } + trigger(this.router, this.state.handlerInfos.slice(0, this.resolveIndex + 1), ignoreFailure, args); + }, + + /** + @public + + Transitions are aborted and their promises rejected + when redirects occur; this method returns a promise + that will follow any redirects that occur and fulfill + with the value fulfilled by any redirecting transitions + that occur. + + @return {Promise} a promise that fulfills with the same + value that the final redirecting transition fulfills with + */ + followRedirects: function() { + var router = this.router; + return this.promise['catch'](function(reason) { + if (router.activeTransition) { + return router.activeTransition.followRedirects(); + } + return Promise.reject(reason); + }); + }, + + toString: function() { + return "Transition (sequence " + this.sequence + ")"; + }, + + /** + @private + */ + log: function(message) { + log(this.router, this.sequence, message); + } + }; + + // Alias 'trigger' as 'send' + Transition.prototype.send = Transition.prototype.trigger; + + /** + @private + + Logs and returns a TransitionAborted error. + */ + function logAbort(transition) { + log(transition.router, transition.sequence, "detected abort."); + return new TransitionAborted(); + } + + function TransitionAborted(message) { + this.message = (message || "TransitionAborted"); + this.name = "TransitionAborted"; + } + + __exports__.Transition = Transition; + __exports__.logAbort = logAbort; + __exports__.TransitionAborted = TransitionAborted; + }); +enifed("router/utils", + ["exports"], + function(__exports__) { + "use strict"; + var slice = Array.prototype.slice; + + var _isArray; + if (!Array.isArray) { + _isArray = function (x) { + return Object.prototype.toString.call(x) === "[object Array]"; + }; + } else { + _isArray = Array.isArray; + } + + var isArray = _isArray; + __exports__.isArray = isArray; + function merge(hash, other) { + for (var prop in other) { + if (other.hasOwnProperty(prop)) { hash[prop] = other[prop]; } + } + } + + var oCreate = Object.create || function(proto) { + function F() {} + F.prototype = proto; + return new F(); + }; + __exports__.oCreate = oCreate; + /** + @private + + Extracts query params from the end of an array + **/ + function extractQueryParams(array) { + var len = (array && array.length), head, queryParams; + + if(len && len > 0 && array[len - 1] && array[len - 1].hasOwnProperty('queryParams')) { + queryParams = array[len - 1].queryParams; + head = slice.call(array, 0, len - 1); + return [head, queryParams]; + } else { + return [array, null]; + } + } + + __exports__.extractQueryParams = extractQueryParams;/** + @private + + Coerces query param properties and array elements into strings. + **/ + function coerceQueryParamsToString(queryParams) { + for (var key in queryParams) { + if (typeof queryParams[key] === 'number') { + queryParams[key] = '' + queryParams[key]; + } else if (isArray(queryParams[key])) { + for (var i = 0, l = queryParams[key].length; i < l; i++) { + queryParams[key][i] = '' + queryParams[key][i]; + } + } + } + } + /** + @private + */ + function log(router, sequence, msg) { + if (!router.log) { return; } + + if (arguments.length === 3) { + router.log("Transition #" + sequence + ": " + msg); + } else { + msg = sequence; + router.log(msg); + } + } + + __exports__.log = log;function bind(context, fn) { + var boundArgs = arguments; + return function(value) { + var args = slice.call(boundArgs, 2); + args.push(value); + return fn.apply(context, args); + }; + } + + __exports__.bind = bind;function isParam(object) { + return (typeof object === "string" || object instanceof String || typeof object === "number" || object instanceof Number); + } + + + function forEach(array, callback) { + for (var i=0, l=array.length; i=0; i--) { + var handlerInfo = handlerInfos[i], + handler = handlerInfo.handler; + + if (handler.events && handler.events[name]) { + if (handler.events[name].apply(handler, args) === true) { + eventWasHandled = true; + } else { + return; + } + } + } + + if (!eventWasHandled && !ignoreFailure) { + throw new Error("Nothing handled the event '" + name + "'."); + } + } + + __exports__.trigger = trigger;function getChangelist(oldObject, newObject) { + var key; + var results = { + all: {}, + changed: {}, + removed: {} + }; + + merge(results.all, newObject); + + var didChange = false; + coerceQueryParamsToString(oldObject); + coerceQueryParamsToString(newObject); + + // Calculate removals + for (key in oldObject) { + if (oldObject.hasOwnProperty(key)) { + if (!newObject.hasOwnProperty(key)) { + didChange = true; + results.removed[key] = oldObject[key]; + } + } + } + + // Calculate changes + for (key in newObject) { + if (newObject.hasOwnProperty(key)) { + if (isArray(oldObject[key]) && isArray(newObject[key])) { + if (oldObject[key].length !== newObject[key].length) { + results.changed[key] = newObject[key]; + didChange = true; + } else { + for (var i = 0, l = oldObject[key].length; i < l; i++) { + if (oldObject[key][i] !== newObject[key][i]) { + results.changed[key] = newObject[key]; + didChange = true; + } + } + } + } + else { + if (oldObject[key] !== newObject[key]) { + results.changed[key] = newObject[key]; + didChange = true; + } + } + } + } + + return didChange && results; + } + + __exports__.getChangelist = getChangelist;function promiseLabel(label) { + return 'Router: ' + label; + } + + __exports__.promiseLabel = promiseLabel;function subclass(parentConstructor, proto) { + function C(props) { + parentConstructor.call(this, props || {}); + } + C.prototype = oCreate(parentConstructor.prototype); + merge(C.prototype, proto); + return C; + } + + __exports__.subclass = subclass;function resolveHook(obj, hookName) { + if (!obj) { return; } + var underscored = "_" + hookName; + return obj[underscored] && underscored || + obj[hookName] && hookName; + } + + function callHook(obj, hookName) { + var args = slice.call(arguments, 2); + return applyHook(obj, hookName, args); + } + + function applyHook(obj, _hookName, args) { + var hookName = resolveHook(obj, _hookName); + if (hookName) { + return obj[hookName].apply(obj, args); + } + } + + __exports__.merge = merge; + __exports__.slice = slice; + __exports__.isParam = isParam; + __exports__.coerceQueryParamsToString = coerceQueryParamsToString; + __exports__.callHook = callHook; + __exports__.resolveHook = resolveHook; + __exports__.applyHook = applyHook; + }); +enifed("rsvp", + ["./rsvp/promise","./rsvp/events","./rsvp/node","./rsvp/all","./rsvp/all-settled","./rsvp/race","./rsvp/hash","./rsvp/hash-settled","./rsvp/rethrow","./rsvp/defer","./rsvp/config","./rsvp/map","./rsvp/resolve","./rsvp/reject","./rsvp/filter","./rsvp/asap","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var EventTarget = __dependency2__["default"]; + var denodeify = __dependency3__["default"]; + var all = __dependency4__["default"]; + var allSettled = __dependency5__["default"]; + var race = __dependency6__["default"]; + var hash = __dependency7__["default"]; + var hashSettled = __dependency8__["default"]; + var rethrow = __dependency9__["default"]; + var defer = __dependency10__["default"]; + var config = __dependency11__.config; + var configure = __dependency11__.configure; + var map = __dependency12__["default"]; + var resolve = __dependency13__["default"]; + var reject = __dependency14__["default"]; + var filter = __dependency15__["default"]; + var asap = __dependency16__["default"]; + + config.async = asap; // default async is asap; + var cast = resolve; + function async(callback, arg) { + config.async(callback, arg); + } + + function on() { + config.on.apply(config, arguments); + } + + function off() { + config.off.apply(config, arguments); + } + + // Set up instrumentation through `window.__PROMISE_INTRUMENTATION__` + if (typeof window !== 'undefined' && typeof window['__PROMISE_INSTRUMENTATION__'] === 'object') { + var callbacks = window['__PROMISE_INSTRUMENTATION__']; + configure('instrument', true); + for (var eventName in callbacks) { + if (callbacks.hasOwnProperty(eventName)) { + on(eventName, callbacks[eventName]); + } + } + } + + __exports__.cast = cast; + __exports__.Promise = Promise; + __exports__.EventTarget = EventTarget; + __exports__.all = all; + __exports__.allSettled = allSettled; + __exports__.race = race; + __exports__.hash = hash; + __exports__.hashSettled = hashSettled; + __exports__.rethrow = rethrow; + __exports__.defer = defer; + __exports__.denodeify = denodeify; + __exports__.configure = configure; + __exports__.on = on; + __exports__.off = off; + __exports__.resolve = resolve; + __exports__.reject = reject; + __exports__.async = async; + __exports__.map = map; + __exports__.filter = filter; + }); +enifed("rsvp.umd", + ["./rsvp"], + function(__dependency1__) { + "use strict"; + var Promise = __dependency1__.Promise; + var allSettled = __dependency1__.allSettled; + var hash = __dependency1__.hash; + var hashSettled = __dependency1__.hashSettled; + var denodeify = __dependency1__.denodeify; + var on = __dependency1__.on; + var off = __dependency1__.off; + var map = __dependency1__.map; + var filter = __dependency1__.filter; + var resolve = __dependency1__.resolve; + var reject = __dependency1__.reject; + var rethrow = __dependency1__.rethrow; + var all = __dependency1__.all; + var defer = __dependency1__.defer; + var EventTarget = __dependency1__.EventTarget; + var configure = __dependency1__.configure; + var race = __dependency1__.race; + var async = __dependency1__.async; + + var RSVP = { + 'race': race, + 'Promise': Promise, + 'allSettled': allSettled, + 'hash': hash, + 'hashSettled': hashSettled, + 'denodeify': denodeify, + 'on': on, + 'off': off, + 'map': map, + 'filter': filter, + 'resolve': resolve, + 'reject': reject, + 'all': all, + 'rethrow': rethrow, + 'defer': defer, + 'EventTarget': EventTarget, + 'configure': configure, + 'async': async + }; + + /* global define:true module:true window: true */ + if (typeof enifed === 'function' && enifed['amd']) { + enifed(function() { return RSVP; }); + } else if (typeof module !== 'undefined' && module['exports']) { + module['exports'] = RSVP; + } else if (typeof this !== 'undefined') { + this['RSVP'] = RSVP; + } + }); +enifed("rsvp/-internal", + ["./utils","./instrument","./config","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var objectOrFunction = __dependency1__.objectOrFunction; + var isFunction = __dependency1__.isFunction; + + var instrument = __dependency2__["default"]; + + var config = __dependency3__.config; + + function withOwnPromise() { + return new TypeError('A promises callback cannot return that same promise.'); + } + + function noop() {} + + var PENDING = void 0; + var FULFILLED = 1; + var REJECTED = 2; + + var GET_THEN_ERROR = new ErrorObject(); + + function getThen(promise) { + try { + return promise.then; + } catch(error) { + GET_THEN_ERROR.error = error; + return GET_THEN_ERROR; + } + } + + function tryThen(then, value, fulfillmentHandler, rejectionHandler) { + try { + then.call(value, fulfillmentHandler, rejectionHandler); + } catch(e) { + return e; + } + } + + function handleForeignThenable(promise, thenable, then) { + config.async(function(promise) { + var sealed = false; + var error = tryThen(then, thenable, function(value) { + if (sealed) { return; } + sealed = true; + if (thenable !== value) { + resolve(promise, value); + } else { + fulfill(promise, value); + } + }, function(reason) { + if (sealed) { return; } + sealed = true; + + reject(promise, reason); + }, 'Settle: ' + (promise._label || ' unknown promise')); + + if (!sealed && error) { + sealed = true; + reject(promise, error); + } + }, promise); + } + + function handleOwnThenable(promise, thenable) { + if (thenable._state === FULFILLED) { + fulfill(promise, thenable._result); + } else if (promise._state === REJECTED) { + reject(promise, thenable._result); + } else { + subscribe(thenable, undefined, function(value) { + if (thenable !== value) { + resolve(promise, value); + } else { + fulfill(promise, value); + } + }, function(reason) { + reject(promise, reason); + }); + } + } + + function handleMaybeThenable(promise, maybeThenable) { + if (maybeThenable.constructor === promise.constructor) { + handleOwnThenable(promise, maybeThenable); + } else { + var then = getThen(maybeThenable); + + if (then === GET_THEN_ERROR) { + reject(promise, GET_THEN_ERROR.error); + } else if (then === undefined) { + fulfill(promise, maybeThenable); + } else if (isFunction(then)) { + handleForeignThenable(promise, maybeThenable, then); + } else { + fulfill(promise, maybeThenable); + } + } + } + + function resolve(promise, value) { + if (promise === value) { + fulfill(promise, value); + } else if (objectOrFunction(value)) { + handleMaybeThenable(promise, value); + } else { + fulfill(promise, value); + } + } + + function publishRejection(promise) { + if (promise._onerror) { + promise._onerror(promise._result); + } + + publish(promise); + } + + function fulfill(promise, value) { + if (promise._state !== PENDING) { return; } + + promise._result = value; + promise._state = FULFILLED; + + if (promise._subscribers.length === 0) { + if (config.instrument) { + instrument('fulfilled', promise); + } + } else { + config.async(publish, promise); + } + } + + function reject(promise, reason) { + if (promise._state !== PENDING) { return; } + promise._state = REJECTED; + promise._result = reason; + + config.async(publishRejection, promise); + } + + function subscribe(parent, child, onFulfillment, onRejection) { + var subscribers = parent._subscribers; + var length = subscribers.length; + + parent._onerror = null; + + subscribers[length] = child; + subscribers[length + FULFILLED] = onFulfillment; + subscribers[length + REJECTED] = onRejection; + + if (length === 0 && parent._state) { + config.async(publish, parent); + } + } + + function publish(promise) { + var subscribers = promise._subscribers; + var settled = promise._state; + + if (config.instrument) { + instrument(settled === FULFILLED ? 'fulfilled' : 'rejected', promise); + } + + if (subscribers.length === 0) { return; } + + var child, callback, detail = promise._result; + + for (var i = 0; i < subscribers.length; i += 3) { + child = subscribers[i]; + callback = subscribers[i + settled]; + + if (child) { + invokeCallback(settled, child, callback, detail); + } else { + callback(detail); + } + } + + promise._subscribers.length = 0; + } + + function ErrorObject() { + this.error = null; + } + + var TRY_CATCH_ERROR = new ErrorObject(); + + function tryCatch(callback, detail) { + try { + return callback(detail); + } catch(e) { + TRY_CATCH_ERROR.error = e; + return TRY_CATCH_ERROR; + } + } + + function invokeCallback(settled, promise, callback, detail) { + var hasCallback = isFunction(callback), + value, error, succeeded, failed; + + if (hasCallback) { + value = tryCatch(callback, detail); + + if (value === TRY_CATCH_ERROR) { + failed = true; + error = value.error; + value = null; + } else { + succeeded = true; + } + + if (promise === value) { + reject(promise, withOwnPromise()); + return; + } + + } else { + value = detail; + succeeded = true; + } + + if (promise._state !== PENDING) { + // noop + } else if (hasCallback && succeeded) { + resolve(promise, value); + } else if (failed) { + reject(promise, error); + } else if (settled === FULFILLED) { + fulfill(promise, value); + } else if (settled === REJECTED) { + reject(promise, value); + } + } + + function initializePromise(promise, resolver) { + try { + resolver(function resolvePromise(value){ + resolve(promise, value); + }, function rejectPromise(reason) { + reject(promise, reason); + }); + } catch(e) { + reject(promise, e); + } + } + + __exports__.noop = noop; + __exports__.resolve = resolve; + __exports__.reject = reject; + __exports__.fulfill = fulfill; + __exports__.subscribe = subscribe; + __exports__.publish = publish; + __exports__.publishRejection = publishRejection; + __exports__.initializePromise = initializePromise; + __exports__.invokeCallback = invokeCallback; + __exports__.FULFILLED = FULFILLED; + __exports__.REJECTED = REJECTED; + __exports__.PENDING = PENDING; + }); +enifed("rsvp/all-settled", + ["./enumerator","./promise","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Enumerator = __dependency1__["default"]; + var makeSettledResult = __dependency1__.makeSettledResult; + var Promise = __dependency2__["default"]; + var o_create = __dependency3__.o_create; + + function AllSettled(Constructor, entries, label) { + this._superConstructor(Constructor, entries, false /* don't abort on reject */, label); + } + + AllSettled.prototype = o_create(Enumerator.prototype); + AllSettled.prototype._superConstructor = Enumerator; + AllSettled.prototype._makeResult = makeSettledResult; + AllSettled.prototype._validationError = function() { + return new Error('allSettled must be called with an array'); + }; + + /** + `RSVP.allSettled` is similar to `RSVP.all`, but instead of implementing + a fail-fast method, it waits until all the promises have returned and + shows you all the results. This is useful if you want to handle multiple + promises' failure states together as a set. + + Returns a promise that is fulfilled when all the given promises have been + settled. The return promise is fulfilled with an array of the states of + the promises passed into the `promises` array argument. + + Each state object will either indicate fulfillment or rejection, and + provide the corresponding value or reason. The states will take one of + the following formats: + + ```javascript + { state: 'fulfilled', value: value } + or + { state: 'rejected', reason: reason } + ``` + + Example: + + ```javascript + var promise1 = RSVP.Promise.resolve(1); + var promise2 = RSVP.Promise.reject(new Error('2')); + var promise3 = RSVP.Promise.reject(new Error('3')); + var promises = [ promise1, promise2, promise3 ]; + + RSVP.allSettled(promises).then(function(array){ + // array == [ + // { state: 'fulfilled', value: 1 }, + // { state: 'rejected', reason: Error }, + // { state: 'rejected', reason: Error } + // ] + // Note that for the second item, reason.message will be '2', and for the + // third item, reason.message will be '3'. + }, function(error) { + // Not run. (This block would only be called if allSettled had failed, + // for instance if passed an incorrect argument type.) + }); + ``` + + @method allSettled + @static + @for RSVP + @param {Array} promises + @param {String} label - optional string that describes the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled with an array of the settled + states of the constituent promises. + */ + + __exports__["default"] = function allSettled(entries, label) { + return new AllSettled(Promise, entries, label).promise; + } + }); +enifed("rsvp/all", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + This is a convenient alias for `RSVP.Promise.all`. + + @method all + @static + @for RSVP + @param {Array} array Array of promises. + @param {String} label An optional label. This is useful + for tooling. + */ + __exports__["default"] = function all(array, label) { + return Promise.all(array, label); + } + }); +enifed("rsvp/asap", + ["exports"], + function(__exports__) { + "use strict"; + var len = 0; + + __exports__["default"] = function asap(callback, arg) { + queue[len] = callback; + queue[len + 1] = arg; + len += 2; + if (len === 2) { + // If len is 1, that means that we need to schedule an async flush. + // If additional callbacks are queued before the queue is flushed, they + // will be processed by this flush that we are scheduling. + scheduleFlush(); + } + } + + var browserWindow = (typeof window !== 'undefined') ? window : undefined + var browserGlobal = browserWindow || {}; + var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver; + + // test for web worker but not in IE10 + var isWorker = typeof Uint8ClampedArray !== 'undefined' && + typeof importScripts !== 'undefined' && + typeof MessageChannel !== 'undefined'; + + // node + function useNextTick() { + return function() { + process.nextTick(flush); + }; + } + + // vertx + function useVertxTimer() { + return function() { + vertxNext(flush); + }; + } + + function useMutationObserver() { + var iterations = 0; + var observer = new BrowserMutationObserver(flush); + var node = document.createTextNode(''); + observer.observe(node, { characterData: true }); + + return function() { + node.data = (iterations = ++iterations % 2); + }; + } + + // web worker + function useMessageChannel() { + var channel = new MessageChannel(); + channel.port1.onmessage = flush; + return function () { + channel.port2.postMessage(0); + }; + } + + function useSetTimeout() { + return function() { + setTimeout(flush, 1); + }; + } + + var queue = new Array(1000); + function flush() { + for (var i = 0; i < len; i+=2) { + var callback = queue[i]; + var arg = queue[i+1]; + + callback(arg); + + queue[i] = undefined; + queue[i+1] = undefined; + } + + len = 0; + } + + function attemptVertex() { + try { + var vertx = eriuqer('vertx'); + var vertxNext = vertx.runOnLoop || vertx.runOnContext; + return useVertxTimer(); + } catch(e) { + return useSetTimeout(); + } + } + + var scheduleFlush; + // Decide what async method to use to triggering processing of queued callbacks: + if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') { + scheduleFlush = useNextTick(); + } else if (BrowserMutationObserver) { + scheduleFlush = useMutationObserver(); + } else if (isWorker) { + scheduleFlush = useMessageChannel(); + } else if (browserWindow === undefined && typeof eriuqer === 'function') { + scheduleFlush = attemptVertex(); + } else { + scheduleFlush = useSetTimeout(); + } + }); +enifed("rsvp/config", + ["./events","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var EventTarget = __dependency1__["default"]; + + var config = { + instrument: false + }; + + EventTarget.mixin(config); + + function configure(name, value) { + if (name === 'onerror') { + // handle for legacy users that expect the actual + // error to be passed to their function added via + // `RSVP.configure('onerror', someFunctionHere);` + config.on('error', value); + return; + } + + if (arguments.length === 2) { + config[name] = value; + } else { + return config[name]; + } + } + + __exports__.config = config; + __exports__.configure = configure; + }); +enifed("rsvp/defer", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + `RSVP.defer` returns an object similar to jQuery's `$.Deferred`. + `RSVP.defer` should be used when porting over code reliant on `$.Deferred`'s + interface. New code should use the `RSVP.Promise` constructor instead. + + The object returned from `RSVP.defer` is a plain object with three properties: + + * promise - an `RSVP.Promise`. + * reject - a function that causes the `promise` property on this object to + become rejected + * resolve - a function that causes the `promise` property on this object to + become fulfilled. + + Example: + + ```javascript + var deferred = RSVP.defer(); + + deferred.resolve("Success!"); + + defered.promise.then(function(value){ + // value here is "Success!" + }); + ``` + + @method defer + @static + @for RSVP + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Object} + */ + + __exports__["default"] = function defer(label) { + var deferred = { }; + + deferred['promise'] = new Promise(function(resolve, reject) { + deferred['resolve'] = resolve; + deferred['reject'] = reject; + }, label); + + return deferred; + } + }); +enifed("rsvp/enumerator", + ["./utils","./-internal","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var isArray = __dependency1__.isArray; + var isMaybeThenable = __dependency1__.isMaybeThenable; + + var noop = __dependency2__.noop; + var reject = __dependency2__.reject; + var fulfill = __dependency2__.fulfill; + var subscribe = __dependency2__.subscribe; + var FULFILLED = __dependency2__.FULFILLED; + var REJECTED = __dependency2__.REJECTED; + var PENDING = __dependency2__.PENDING; + + function makeSettledResult(state, position, value) { + if (state === FULFILLED) { + return { + state: 'fulfilled', + value: value + }; + } else { + return { + state: 'rejected', + reason: value + }; + } + } + + __exports__.makeSettledResult = makeSettledResult;function Enumerator(Constructor, input, abortOnReject, label) { + this._instanceConstructor = Constructor; + this.promise = new Constructor(noop, label); + this._abortOnReject = abortOnReject; + + if (this._validateInput(input)) { + this._input = input; + this.length = input.length; + this._remaining = input.length; + + this._init(); + + if (this.length === 0) { + fulfill(this.promise, this._result); + } else { + this.length = this.length || 0; + this._enumerate(); + if (this._remaining === 0) { + fulfill(this.promise, this._result); + } + } + } else { + reject(this.promise, this._validationError()); + } + } + + Enumerator.prototype._validateInput = function(input) { + return isArray(input); + }; + + Enumerator.prototype._validationError = function() { + return new Error('Array Methods must be provided an Array'); + }; + + Enumerator.prototype._init = function() { + this._result = new Array(this.length); + }; + + __exports__["default"] = Enumerator; + + Enumerator.prototype._enumerate = function() { + var length = this.length; + var promise = this.promise; + var input = this._input; + + for (var i = 0; promise._state === PENDING && i < length; i++) { + this._eachEntry(input[i], i); + } + }; + + Enumerator.prototype._eachEntry = function(entry, i) { + var c = this._instanceConstructor; + if (isMaybeThenable(entry)) { + if (entry.constructor === c && entry._state !== PENDING) { + entry._onerror = null; + this._settledAt(entry._state, i, entry._result); + } else { + this._willSettleAt(c.resolve(entry), i); + } + } else { + this._remaining--; + this._result[i] = this._makeResult(FULFILLED, i, entry); + } + }; + + Enumerator.prototype._settledAt = function(state, i, value) { + var promise = this.promise; + + if (promise._state === PENDING) { + this._remaining--; + + if (this._abortOnReject && state === REJECTED) { + reject(promise, value); + } else { + this._result[i] = this._makeResult(state, i, value); + } + } + + if (this._remaining === 0) { + fulfill(promise, this._result); + } + }; + + Enumerator.prototype._makeResult = function(state, i, value) { + return value; + }; + + Enumerator.prototype._willSettleAt = function(promise, i) { + var enumerator = this; + + subscribe(promise, undefined, function(value) { + enumerator._settledAt(FULFILLED, i, value); + }, function(reason) { + enumerator._settledAt(REJECTED, i, reason); + }); + }; + }); +enifed("rsvp/events", + ["exports"], + function(__exports__) { + "use strict"; + function indexOf(callbacks, callback) { + for (var i=0, l=callbacks.length; i 1; + }; + + RSVP.filter(promises, filterFn).then(function(result){ + // result is [ 2, 3 ] + }); + ``` + + If any of the `promises` given to `RSVP.filter` are rejected, the first promise + that is rejected will be given as an argument to the returned promise's + rejection handler. For example: + + ```javascript + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.reject(new Error('2')); + var promise3 = RSVP.reject(new Error('3')); + var promises = [ promise1, promise2, promise3 ]; + + var filterFn = function(item){ + return item > 1; + }; + + RSVP.filter(promises, filterFn).then(function(array){ + // Code here never runs because there are rejected promises! + }, function(reason) { + // reason.message === '2' + }); + ``` + + `RSVP.filter` will also wait for any promises returned from `filterFn`. + For instance, you may want to fetch a list of users then return a subset + of those users based on some asynchronous operation: + + ```javascript + + var alice = { name: 'alice' }; + var bob = { name: 'bob' }; + var users = [ alice, bob ]; + + var promises = users.map(function(user){ + return RSVP.resolve(user); + }); + + var filterFn = function(user){ + // Here, Alice has permissions to create a blog post, but Bob does not. + return getPrivilegesForUser(user).then(function(privs){ + return privs.can_create_blog_post === true; + }); + }; + RSVP.filter(promises, filterFn).then(function(users){ + // true, because the server told us only Alice can create a blog post. + users.length === 1; + // false, because Alice is the only user present in `users` + users[0] === bob; + }); + ``` + + @method filter + @static + @for RSVP + @param {Array} promises + @param {Function} filterFn - function to be called on each resolved value to + filter the final results. + @param {String} label optional string describing the promise. Useful for + tooling. + @return {Promise} + */ + __exports__["default"] = function filter(promises, filterFn, label) { + return Promise.all(promises, label).then(function(values) { + if (!isFunction(filterFn)) { + throw new TypeError("You must pass a function as filter's second argument."); + } + + var length = values.length; + var filtered = new Array(length); + + for (var i = 0; i < length; i++) { + filtered[i] = filterFn(values[i]); + } + + return Promise.all(filtered, label).then(function(filtered) { + var results = new Array(length); + var newLength = 0; + + for (var i = 0; i < length; i++) { + if (filtered[i]) { + results[newLength] = values[i]; + newLength++; + } + } + + results.length = newLength; + + return results; + }); + }); + } + }); +enifed("rsvp/hash-settled", + ["./promise","./enumerator","./promise-hash","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var makeSettledResult = __dependency2__.makeSettledResult; + var PromiseHash = __dependency3__["default"]; + var Enumerator = __dependency2__["default"]; + var o_create = __dependency4__.o_create; + + function HashSettled(Constructor, object, label) { + this._superConstructor(Constructor, object, false, label); + } + + HashSettled.prototype = o_create(PromiseHash.prototype); + HashSettled.prototype._superConstructor = Enumerator; + HashSettled.prototype._makeResult = makeSettledResult; + + HashSettled.prototype._validationError = function() { + return new Error('hashSettled must be called with an object'); + }; + + /** + `RSVP.hashSettled` is similar to `RSVP.allSettled`, but takes an object + instead of an array for its `promises` argument. + + Unlike `RSVP.all` or `RSVP.hash`, which implement a fail-fast method, + but like `RSVP.allSettled`, `hashSettled` waits until all the + constituent promises have returned and then shows you all the results + with their states and values/reasons. This is useful if you want to + handle multiple promises' failure states together as a set. + + Returns a promise that is fulfilled when all the given promises have been + settled, or rejected if the passed parameters are invalid. + + The returned promise is fulfilled with a hash that has the same key names as + the `promises` object argument. If any of the values in the object are not + promises, they will be copied over to the fulfilled object and marked with state + 'fulfilled'. + + Example: + + ```javascript + var promises = { + myPromise: RSVP.Promise.resolve(1), + yourPromise: RSVP.Promise.resolve(2), + theirPromise: RSVP.Promise.resolve(3), + notAPromise: 4 + }; + + RSVP.hashSettled(promises).then(function(hash){ + // hash here is an object that looks like: + // { + // myPromise: { state: 'fulfilled', value: 1 }, + // yourPromise: { state: 'fulfilled', value: 2 }, + // theirPromise: { state: 'fulfilled', value: 3 }, + // notAPromise: { state: 'fulfilled', value: 4 } + // } + }); + ``` + + If any of the `promises` given to `RSVP.hash` are rejected, the state will + be set to 'rejected' and the reason for rejection provided. + + Example: + + ```javascript + var promises = { + myPromise: RSVP.Promise.resolve(1), + rejectedPromise: RSVP.Promise.reject(new Error('rejection')), + anotherRejectedPromise: RSVP.Promise.reject(new Error('more rejection')), + }; + + RSVP.hashSettled(promises).then(function(hash){ + // hash here is an object that looks like: + // { + // myPromise: { state: 'fulfilled', value: 1 }, + // rejectedPromise: { state: 'rejected', reason: Error }, + // anotherRejectedPromise: { state: 'rejected', reason: Error }, + // } + // Note that for rejectedPromise, reason.message == 'rejection', + // and for anotherRejectedPromise, reason.message == 'more rejection'. + }); + ``` + + An important note: `RSVP.hashSettled` is intended for plain JavaScript objects that + are just a set of keys and values. `RSVP.hashSettled` will NOT preserve prototype + chains. + + Example: + + ```javascript + function MyConstructor(){ + this.example = RSVP.Promise.resolve('Example'); + } + + MyConstructor.prototype = { + protoProperty: RSVP.Promise.resolve('Proto Property') + }; + + var myObject = new MyConstructor(); + + RSVP.hashSettled(myObject).then(function(hash){ + // protoProperty will not be present, instead you will just have an + // object that looks like: + // { + // example: { state: 'fulfilled', value: 'Example' } + // } + // + // hash.hasOwnProperty('protoProperty'); // false + // 'undefined' === typeof hash.protoProperty + }); + ``` + + @method hashSettled + @for RSVP + @param {Object} promises + @param {String} label optional string that describes the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled when when all properties of `promises` + have been settled. + @static + */ + __exports__["default"] = function hashSettled(object, label) { + return new HashSettled(Promise, object, label).promise; + } + }); +enifed("rsvp/hash", + ["./promise","./promise-hash","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var PromiseHash = __dependency2__["default"]; + + /** + `RSVP.hash` is similar to `RSVP.all`, but takes an object instead of an array + for its `promises` argument. + + Returns a promise that is fulfilled when all the given promises have been + fulfilled, or rejected if any of them become rejected. The returned promise + is fulfilled with a hash that has the same key names as the `promises` object + argument. If any of the values in the object are not promises, they will + simply be copied over to the fulfilled object. + + Example: + + ```javascript + var promises = { + myPromise: RSVP.resolve(1), + yourPromise: RSVP.resolve(2), + theirPromise: RSVP.resolve(3), + notAPromise: 4 + }; + + RSVP.hash(promises).then(function(hash){ + // hash here is an object that looks like: + // { + // myPromise: 1, + // yourPromise: 2, + // theirPromise: 3, + // notAPromise: 4 + // } + }); + ```` + + If any of the `promises` given to `RSVP.hash` are rejected, the first promise + that is rejected will be given as the reason to the rejection handler. + + Example: + + ```javascript + var promises = { + myPromise: RSVP.resolve(1), + rejectedPromise: RSVP.reject(new Error('rejectedPromise')), + anotherRejectedPromise: RSVP.reject(new Error('anotherRejectedPromise')), + }; + + RSVP.hash(promises).then(function(hash){ + // Code here never runs because there are rejected promises! + }, function(reason) { + // reason.message === 'rejectedPromise' + }); + ``` + + An important note: `RSVP.hash` is intended for plain JavaScript objects that + are just a set of keys and values. `RSVP.hash` will NOT preserve prototype + chains. + + Example: + + ```javascript + function MyConstructor(){ + this.example = RSVP.resolve('Example'); + } + + MyConstructor.prototype = { + protoProperty: RSVP.resolve('Proto Property') + }; + + var myObject = new MyConstructor(); + + RSVP.hash(myObject).then(function(hash){ + // protoProperty will not be present, instead you will just have an + // object that looks like: + // { + // example: 'Example' + // } + // + // hash.hasOwnProperty('protoProperty'); // false + // 'undefined' === typeof hash.protoProperty + }); + ``` + + @method hash + @static + @for RSVP + @param {Object} promises + @param {String} label optional string that describes the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled when all properties of `promises` + have been fulfilled, or rejected if any of them become rejected. + */ + __exports__["default"] = function hash(object, label) { + return new PromiseHash(Promise, object, label).promise; + } + }); +enifed("rsvp/instrument", + ["./config","./utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var config = __dependency1__.config; + var now = __dependency2__.now; + + var queue = []; + + function scheduleFlush() { + setTimeout(function() { + var entry; + for (var i = 0; i < queue.length; i++) { + entry = queue[i]; + + var payload = entry.payload; + + payload.guid = payload.key + payload.id; + payload.childGuid = payload.key + payload.childId; + if (payload.error) { + payload.stack = payload.error.stack; + } + + config.trigger(entry.name, entry.payload); + } + queue.length = 0; + }, 50); + } + + __exports__["default"] = function instrument(eventName, promise, child) { + if (1 === queue.push({ + name: eventName, + payload: { + key: promise._guidKey, + id: promise._id, + eventName: eventName, + detail: promise._result, + childId: child && child._id, + label: promise._label, + timeStamp: now(), + error: config["instrument-with-stack"] ? new Error(promise._label) : null + }})) { + scheduleFlush(); + } + } + }); +enifed("rsvp/map", + ["./promise","./utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var isFunction = __dependency2__.isFunction; + + /** + `RSVP.map` is similar to JavaScript's native `map` method, except that it + waits for all promises to become fulfilled before running the `mapFn` on + each item in given to `promises`. `RSVP.map` returns a promise that will + become fulfilled with the result of running `mapFn` on the values the promises + become fulfilled with. + + For example: + + ```javascript + + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.resolve(2); + var promise3 = RSVP.resolve(3); + var promises = [ promise1, promise2, promise3 ]; + + var mapFn = function(item){ + return item + 1; + }; + + RSVP.map(promises, mapFn).then(function(result){ + // result is [ 2, 3, 4 ] + }); + ``` + + If any of the `promises` given to `RSVP.map` are rejected, the first promise + that is rejected will be given as an argument to the returned promise's + rejection handler. For example: + + ```javascript + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.reject(new Error('2')); + var promise3 = RSVP.reject(new Error('3')); + var promises = [ promise1, promise2, promise3 ]; + + var mapFn = function(item){ + return item + 1; + }; + + RSVP.map(promises, mapFn).then(function(array){ + // Code here never runs because there are rejected promises! + }, function(reason) { + // reason.message === '2' + }); + ``` + + `RSVP.map` will also wait if a promise is returned from `mapFn`. For example, + say you want to get all comments from a set of blog posts, but you need + the blog posts first because they contain a url to those comments. + + ```javscript + + var mapFn = function(blogPost){ + // getComments does some ajax and returns an RSVP.Promise that is fulfilled + // with some comments data + return getComments(blogPost.comments_url); + }; + + // getBlogPosts does some ajax and returns an RSVP.Promise that is fulfilled + // with some blog post data + RSVP.map(getBlogPosts(), mapFn).then(function(comments){ + // comments is the result of asking the server for the comments + // of all blog posts returned from getBlogPosts() + }); + ``` + + @method map + @static + @for RSVP + @param {Array} promises + @param {Function} mapFn function to be called on each fulfilled promise. + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled with the result of calling + `mapFn` on each fulfilled promise or value when they become fulfilled. + The promise will be rejected if any of the given `promises` become rejected. + @static + */ + __exports__["default"] = function map(promises, mapFn, label) { + return Promise.all(promises, label).then(function(values) { + if (!isFunction(mapFn)) { + throw new TypeError("You must pass a function as map's second argument."); + } + + var length = values.length; + var results = new Array(length); + + for (var i = 0; i < length; i++) { + results[i] = mapFn(values[i]); + } + + return Promise.all(results, label); + }); + } + }); +enifed("rsvp/node", + ["./promise","./-internal","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var noop = __dependency2__.noop; + var resolve = __dependency2__.resolve; + var reject = __dependency2__.reject; + var isArray = __dependency3__.isArray; + + function Result() { + this.value = undefined; + } + + var ERROR = new Result(); + var GET_THEN_ERROR = new Result(); + + function getThen(obj) { + try { + return obj.then; + } catch(error) { + ERROR.value= error; + return ERROR; + } + } + + + function tryApply(f, s, a) { + try { + f.apply(s, a); + } catch(error) { + ERROR.value = error; + return ERROR; + } + } + + function makeObject(_, argumentNames) { + var obj = {}; + var name; + var i; + var length = _.length; + var args = new Array(length); + + for (var x = 0; x < length; x++) { + args[x] = _[x]; + } + + for (i = 0; i < argumentNames.length; i++) { + name = argumentNames[i]; + obj[name] = args[i + 1]; + } + + return obj; + } + + function arrayResult(_) { + var length = _.length; + var args = new Array(length - 1); + + for (var i = 1; i < length; i++) { + args[i - 1] = _[i]; + } + + return args; + } + + function wrapThenable(then, promise) { + return { + then: function(onFulFillment, onRejection) { + return then.call(promise, onFulFillment, onRejection); + } + }; + } + + /** + `RSVP.denodeify` takes a 'node-style' function and returns a function that + will return an `RSVP.Promise`. You can use `denodeify` in Node.js or the + browser when you'd prefer to use promises over using callbacks. For example, + `denodeify` transforms the following: + + ```javascript + var fs = require('fs'); + + fs.readFile('myfile.txt', function(err, data){ + if (err) return handleError(err); + handleData(data); + }); + ``` + + into: + + ```javascript + var fs = require('fs'); + var readFile = RSVP.denodeify(fs.readFile); + + readFile('myfile.txt').then(handleData, handleError); + ``` + + If the node function has multiple success parameters, then `denodeify` + just returns the first one: + + ```javascript + var request = RSVP.denodeify(require('request')); + + request('http://example.com').then(function(res) { + // ... + }); + ``` + + However, if you need all success parameters, setting `denodeify`'s + second parameter to `true` causes it to return all success parameters + as an array: + + ```javascript + var request = RSVP.denodeify(require('request'), true); + + request('http://example.com').then(function(result) { + // result[0] -> res + // result[1] -> body + }); + ``` + + Or if you pass it an array with names it returns the parameters as a hash: + + ```javascript + var request = RSVP.denodeify(require('request'), ['res', 'body']); + + request('http://example.com').then(function(result) { + // result.res + // result.body + }); + ``` + + Sometimes you need to retain the `this`: + + ```javascript + var app = require('express')(); + var render = RSVP.denodeify(app.render.bind(app)); + ``` + + The denodified function inherits from the original function. It works in all + environments, except IE 10 and below. Consequently all properties of the original + function are available to you. However, any properties you change on the + denodeified function won't be changed on the original function. Example: + + ```javascript + var request = RSVP.denodeify(require('request')), + cookieJar = request.jar(); // <- Inheritance is used here + + request('http://example.com', {jar: cookieJar}).then(function(res) { + // cookieJar.cookies holds now the cookies returned by example.com + }); + ``` + + Using `denodeify` makes it easier to compose asynchronous operations instead + of using callbacks. For example, instead of: + + ```javascript + var fs = require('fs'); + + fs.readFile('myfile.txt', function(err, data){ + if (err) { ... } // Handle error + fs.writeFile('myfile2.txt', data, function(err){ + if (err) { ... } // Handle error + console.log('done') + }); + }); + ``` + + you can chain the operations together using `then` from the returned promise: + + ```javascript + var fs = require('fs'); + var readFile = RSVP.denodeify(fs.readFile); + var writeFile = RSVP.denodeify(fs.writeFile); + + readFile('myfile.txt').then(function(data){ + return writeFile('myfile2.txt', data); + }).then(function(){ + console.log('done') + }).catch(function(error){ + // Handle error + }); + ``` + + @method denodeify + @static + @for RSVP + @param {Function} nodeFunc a 'node-style' function that takes a callback as + its last argument. The callback expects an error to be passed as its first + argument (if an error occurred, otherwise null), and the value from the + operation as its second argument ('function(err, value){ }'). + @param {Boolean|Array} argumentNames An optional paramter that if set + to `true` causes the promise to fulfill with the callback's success arguments + as an array. This is useful if the node function has multiple success + paramters. If you set this paramter to an array with names, the promise will + fulfill with a hash with these names as keys and the success parameters as + values. + @return {Function} a function that wraps `nodeFunc` to return an + `RSVP.Promise` + @static + */ + __exports__["default"] = function denodeify(nodeFunc, options) { + var fn = function() { + var self = this; + var l = arguments.length; + var args = new Array(l + 1); + var arg; + var promiseInput = false; + + for (var i = 0; i < l; ++i) { + arg = arguments[i]; + + if (!promiseInput) { + // TODO: clean this up + promiseInput = needsPromiseInput(arg); + if (promiseInput === GET_THEN_ERROR) { + var p = new Promise(noop); + reject(p, GET_THEN_ERROR.value); + return p; + } else if (promiseInput && promiseInput !== true) { + arg = wrapThenable(promiseInput, arg); + } + } + args[i] = arg; + } + + var promise = new Promise(noop); + + args[l] = function(err, val) { + if (err) + reject(promise, err); + else if (options === undefined) + resolve(promise, val); + else if (options === true) + resolve(promise, arrayResult(arguments)); + else if (isArray(options)) + resolve(promise, makeObject(arguments, options)); + else + resolve(promise, val); + }; + + if (promiseInput) { + return handlePromiseInput(promise, args, nodeFunc, self); + } else { + return handleValueInput(promise, args, nodeFunc, self); + } + }; + + fn.__proto__ = nodeFunc; + + return fn; + } + + function handleValueInput(promise, args, nodeFunc, self) { + var result = tryApply(nodeFunc, self, args); + if (result === ERROR) { + reject(promise, result.value); + } + return promise; + } + + function handlePromiseInput(promise, args, nodeFunc, self){ + return Promise.all(args).then(function(args){ + var result = tryApply(nodeFunc, self, args); + if (result === ERROR) { + reject(promise, result.value); + } + return promise; + }); + } + + function needsPromiseInput(arg) { + if (arg && typeof arg === 'object') { + if (arg.constructor === Promise) { + return true; + } else { + return getThen(arg); + } + } else { + return false; + } + } + }); +enifed("rsvp/promise-hash", + ["./enumerator","./-internal","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Enumerator = __dependency1__["default"]; + var PENDING = __dependency2__.PENDING; + var o_create = __dependency3__.o_create; + + function PromiseHash(Constructor, object, label) { + this._superConstructor(Constructor, object, true, label); + } + + __exports__["default"] = PromiseHash; + + PromiseHash.prototype = o_create(Enumerator.prototype); + PromiseHash.prototype._superConstructor = Enumerator; + PromiseHash.prototype._init = function() { + this._result = {}; + }; + + PromiseHash.prototype._validateInput = function(input) { + return input && typeof input === 'object'; + }; + + PromiseHash.prototype._validationError = function() { + return new Error('Promise.hash must be called with an object'); + }; + + PromiseHash.prototype._enumerate = function() { + var promise = this.promise; + var input = this._input; + var results = []; + + for (var key in input) { + if (promise._state === PENDING && input.hasOwnProperty(key)) { + results.push({ + position: key, + entry: input[key] + }); + } + } + + var length = results.length; + this._remaining = length; + var result; + + for (var i = 0; promise._state === PENDING && i < length; i++) { + result = results[i]; + this._eachEntry(result.entry, result.position); + } + }; + }); +enifed("rsvp/promise", + ["./config","./instrument","./utils","./-internal","./promise/all","./promise/race","./promise/resolve","./promise/reject","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var config = __dependency1__.config; + var instrument = __dependency2__["default"]; + + var isFunction = __dependency3__.isFunction; + var now = __dependency3__.now; + + var noop = __dependency4__.noop; + var subscribe = __dependency4__.subscribe; + var initializePromise = __dependency4__.initializePromise; + var invokeCallback = __dependency4__.invokeCallback; + var FULFILLED = __dependency4__.FULFILLED; + var REJECTED = __dependency4__.REJECTED; + + var all = __dependency5__["default"]; + var race = __dependency6__["default"]; + var Resolve = __dependency7__["default"]; + var Reject = __dependency8__["default"]; + + var guidKey = 'rsvp_' + now() + '-'; + var counter = 0; + + function needsResolver() { + throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); + } + + function needsNew() { + throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); + } + __exports__["default"] = Promise; + /** + Promise objects represent the eventual result of an asynchronous operation. The + primary way of interacting with a promise is through its `then` method, which + registers callbacks to receive either a promise’s eventual value or the reason + why the promise cannot be fulfilled. + + Terminology + ----------- + + - `promise` is an object or function with a `then` method whose behavior conforms to this specification. + - `thenable` is an object or function that defines a `then` method. + - `value` is any legal JavaScript value (including undefined, a thenable, or a promise). + - `exception` is a value that is thrown using the throw statement. + - `reason` is a value that indicates why a promise was rejected. + - `settled` the final resting state of a promise, fulfilled or rejected. + + A promise can be in one of three states: pending, fulfilled, or rejected. + + Promises that are fulfilled have a fulfillment value and are in the fulfilled + state. Promises that are rejected have a rejection reason and are in the + rejected state. A fulfillment value is never a thenable. + + Promises can also be said to *resolve* a value. If this value is also a + promise, then the original promise's settled state will match the value's + settled state. So a promise that *resolves* a promise that rejects will + itself reject, and a promise that *resolves* a promise that fulfills will + itself fulfill. + + + Basic Usage: + ------------ + + ```js + var promise = new Promise(function(resolve, reject) { + // on success + resolve(value); + + // on failure + reject(reason); + }); + + promise.then(function(value) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Advanced Usage: + --------------- + + Promises shine when abstracting away asynchronous interactions such as + `XMLHttpRequest`s. + + ```js + function getJSON(url) { + return new Promise(function(resolve, reject){ + var xhr = new XMLHttpRequest(); + + xhr.open('GET', url); + xhr.onreadystatechange = handler; + xhr.responseType = 'json'; + xhr.setRequestHeader('Accept', 'application/json'); + xhr.send(); + + function handler() { + if (this.readyState === this.DONE) { + if (this.status === 200) { + resolve(this.response); + } else { + reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']')); + } + } + }; + }); + } + + getJSON('/posts.json').then(function(json) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Unlike callbacks, promises are great composable primitives. + + ```js + Promise.all([ + getJSON('/posts'), + getJSON('/comments') + ]).then(function(values){ + values[0] // => postsJSON + values[1] // => commentsJSON + + return values; + }); + ``` + + @class RSVP.Promise + @param {function} resolver + @param {String} label optional string for labeling the promise. + Useful for tooling. + @constructor + */ + function Promise(resolver, label) { + this._id = counter++; + this._label = label; + this._state = undefined; + this._result = undefined; + this._subscribers = []; + + if (config.instrument) { + instrument('created', this); + } + + if (noop !== resolver) { + if (!isFunction(resolver)) { + needsResolver(); + } + + if (!(this instanceof Promise)) { + needsNew(); + } + + initializePromise(this, resolver); + } + } + + Promise.cast = Resolve; // deprecated + Promise.all = all; + Promise.race = race; + Promise.resolve = Resolve; + Promise.reject = Reject; + + Promise.prototype = { + constructor: Promise, + + _guidKey: guidKey, + + _onerror: function (reason) { + config.trigger('error', reason); + }, + + /** + The primary way of interacting with a promise is through its `then` method, + which registers callbacks to receive either a promise's eventual value or the + reason why the promise cannot be fulfilled. + + ```js + findUser().then(function(user){ + // user is available + }, function(reason){ + // user is unavailable, and you are given the reason why + }); + ``` + + Chaining + -------- + + The return value of `then` is itself a promise. This second, 'downstream' + promise is resolved with the return value of the first promise's fulfillment + or rejection handler, or rejected if the handler throws an exception. + + ```js + findUser().then(function (user) { + return user.name; + }, function (reason) { + return 'default name'; + }).then(function (userName) { + // If `findUser` fulfilled, `userName` will be the user's name, otherwise it + // will be `'default name'` + }); + + findUser().then(function (user) { + throw new Error('Found user, but still unhappy'); + }, function (reason) { + throw new Error('`findUser` rejected and we're unhappy'); + }).then(function (value) { + // never reached + }, function (reason) { + // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'. + // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'. + }); + ``` + If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. + + ```js + findUser().then(function (user) { + throw new PedagogicalException('Upstream error'); + }).then(function (value) { + // never reached + }).then(function (value) { + // never reached + }, function (reason) { + // The `PedgagocialException` is propagated all the way down to here + }); + ``` + + Assimilation + ------------ + + Sometimes the value you want to propagate to a downstream promise can only be + retrieved asynchronously. This can be achieved by returning a promise in the + fulfillment or rejection handler. The downstream promise will then be pending + until the returned promise is settled. This is called *assimilation*. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // The user's comments are now available + }); + ``` + + If the assimliated promise rejects, then the downstream promise will also reject. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // If `findCommentsByAuthor` fulfills, we'll have the value here + }, function (reason) { + // If `findCommentsByAuthor` rejects, we'll have the reason here + }); + ``` + + Simple Example + -------------- + + Synchronous Example + + ```javascript + var result; + + try { + result = findResult(); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + findResult(function(result, err){ + if (err) { + // failure + } else { + // success + } + }); + ``` + + Promise Example; + + ```javascript + findResult().then(function(result){ + // success + }, function(reason){ + // failure + }); + ``` + + Advanced Example + -------------- + + Synchronous Example + + ```javascript + var author, books; + + try { + author = findAuthor(); + books = findBooksByAuthor(author); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + + function foundBooks(books) { + + } + + function failure(reason) { + + } + + findAuthor(function(author, err){ + if (err) { + failure(err); + // failure + } else { + try { + findBoooksByAuthor(author, function(books, err) { + if (err) { + failure(err); + } else { + try { + foundBooks(books); + } catch(reason) { + failure(reason); + } + } + }); + } catch(error) { + failure(err); + } + // success + } + }); + ``` + + Promise Example; + + ```javascript + findAuthor(). + then(findBooksByAuthor). + then(function(books){ + // found books + }).catch(function(reason){ + // something went wrong + }); + ``` + + @method then + @param {Function} onFulfilled + @param {Function} onRejected + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + then: function(onFulfillment, onRejection, label) { + var parent = this; + var state = parent._state; + + if (state === FULFILLED && !onFulfillment || state === REJECTED && !onRejection) { + if (config.instrument) { + instrument('chained', this, this); + } + return this; + } + + parent._onerror = null; + + var child = new this.constructor(noop, label); + var result = parent._result; + + if (config.instrument) { + instrument('chained', parent, child); + } + + if (state) { + var callback = arguments[state - 1]; + config.async(function(){ + invokeCallback(state, child, callback, result); + }); + } else { + subscribe(parent, child, onFulfillment, onRejection); + } + + return child; + }, + + /** + `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same + as the catch block of a try/catch statement. + + ```js + function findAuthor(){ + throw new Error('couldn't find that author'); + } + + // synchronous + try { + findAuthor(); + } catch(reason) { + // something went wrong + } + + // async with promises + findAuthor().catch(function(reason){ + // something went wrong + }); + ``` + + @method catch + @param {Function} onRejection + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + 'catch': function(onRejection, label) { + return this.then(null, onRejection, label); + }, + + /** + `finally` will be invoked regardless of the promise's fate just as native + try/catch/finally behaves + + Synchronous example: + + ```js + findAuthor() { + if (Math.random() > 0.5) { + throw new Error(); + } + return new Author(); + } + + try { + return findAuthor(); // succeed or fail + } catch(error) { + return findOtherAuther(); + } finally { + // always runs + // doesn't affect the return value + } + ``` + + Asynchronous example: + + ```js + findAuthor().catch(function(reason){ + return findOtherAuther(); + }).finally(function(){ + // author was either found, or not + }); + ``` + + @method finally + @param {Function} callback + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + 'finally': function(callback, label) { + var constructor = this.constructor; + + return this.then(function(value) { + return constructor.resolve(callback()).then(function(){ + return value; + }); + }, function(reason) { + return constructor.resolve(callback()).then(function(){ + throw reason; + }); + }, label); + } + }; + }); +enifed("rsvp/promise/all", + ["../enumerator","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Enumerator = __dependency1__["default"]; + + /** + `RSVP.Promise.all` accepts an array of promises, and returns a new promise which + is fulfilled with an array of fulfillment values for the passed promises, or + rejected with the reason of the first passed promise to be rejected. It casts all + elements of the passed iterable to promises as it runs this algorithm. + + Example: + + ```javascript + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.resolve(2); + var promise3 = RSVP.resolve(3); + var promises = [ promise1, promise2, promise3 ]; + + RSVP.Promise.all(promises).then(function(array){ + // The array here would be [ 1, 2, 3 ]; + }); + ``` + + If any of the `promises` given to `RSVP.all` are rejected, the first promise + that is rejected will be given as an argument to the returned promises's + rejection handler. For example: + + Example: + + ```javascript + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.reject(new Error("2")); + var promise3 = RSVP.reject(new Error("3")); + var promises = [ promise1, promise2, promise3 ]; + + RSVP.Promise.all(promises).then(function(array){ + // Code here never runs because there are rejected promises! + }, function(error) { + // error.message === "2" + }); + ``` + + @method all + @static + @param {Array} entries array of promises + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled when all `promises` have been + fulfilled, or rejected if any of them become rejected. + @static + */ + __exports__["default"] = function all(entries, label) { + return new Enumerator(this, entries, true /* abort on reject */, label).promise; + } + }); +enifed("rsvp/promise/race", + ["../utils","../-internal","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var isArray = __dependency1__.isArray; + + var noop = __dependency2__.noop; + var resolve = __dependency2__.resolve; + var reject = __dependency2__.reject; + var subscribe = __dependency2__.subscribe; + var PENDING = __dependency2__.PENDING; + + /** + `RSVP.Promise.race` returns a new promise which is settled in the same way as the + first passed promise to settle. + + Example: + + ```javascript + var promise1 = new RSVP.Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 1'); + }, 200); + }); + + var promise2 = new RSVP.Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 2'); + }, 100); + }); + + RSVP.Promise.race([promise1, promise2]).then(function(result){ + // result === 'promise 2' because it was resolved before promise1 + // was resolved. + }); + ``` + + `RSVP.Promise.race` is deterministic in that only the state of the first + settled promise matters. For example, even if other promises given to the + `promises` array argument are resolved, but the first settled promise has + become rejected before the other promises became fulfilled, the returned + promise will become rejected: + + ```javascript + var promise1 = new RSVP.Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 1'); + }, 200); + }); + + var promise2 = new RSVP.Promise(function(resolve, reject){ + setTimeout(function(){ + reject(new Error('promise 2')); + }, 100); + }); + + RSVP.Promise.race([promise1, promise2]).then(function(result){ + // Code here never runs + }, function(reason){ + // reason.message === 'promise 2' because promise 2 became rejected before + // promise 1 became fulfilled + }); + ``` + + An example real-world use case is implementing timeouts: + + ```javascript + RSVP.Promise.race([ajax('foo.json'), timeout(5000)]) + ``` + + @method race + @static + @param {Array} promises array of promises to observe + @param {String} label optional string for describing the promise returned. + Useful for tooling. + @return {Promise} a promise which settles in the same way as the first passed + promise to settle. + */ + __exports__["default"] = function race(entries, label) { + /*jshint validthis:true */ + var Constructor = this; + + var promise = new Constructor(noop, label); + + if (!isArray(entries)) { + reject(promise, new TypeError('You must pass an array to race.')); + return promise; + } + + var length = entries.length; + + function onFulfillment(value) { + resolve(promise, value); + } + + function onRejection(reason) { + reject(promise, reason); + } + + for (var i = 0; promise._state === PENDING && i < length; i++) { + subscribe(Constructor.resolve(entries[i]), undefined, onFulfillment, onRejection); + } + + return promise; + } + }); +enifed("rsvp/promise/reject", + ["../-internal","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var noop = __dependency1__.noop; + var _reject = __dependency1__.reject; + + /** + `RSVP.Promise.reject` returns a promise rejected with the passed `reason`. + It is shorthand for the following: + + ```javascript + var promise = new RSVP.Promise(function(resolve, reject){ + reject(new Error('WHOOPS')); + }); + + promise.then(function(value){ + // Code here doesn't run because the promise is rejected! + }, function(reason){ + // reason.message === 'WHOOPS' + }); + ``` + + Instead of writing the above, your code now simply becomes the following: + + ```javascript + var promise = RSVP.Promise.reject(new Error('WHOOPS')); + + promise.then(function(value){ + // Code here doesn't run because the promise is rejected! + }, function(reason){ + // reason.message === 'WHOOPS' + }); + ``` + + @method reject + @static + @param {Any} reason value that the returned promise will be rejected with. + @param {String} label optional string for identifying the returned promise. + Useful for tooling. + @return {Promise} a promise rejected with the given `reason`. + */ + __exports__["default"] = function reject(reason, label) { + /*jshint validthis:true */ + var Constructor = this; + var promise = new Constructor(noop, label); + _reject(promise, reason); + return promise; + } + }); +enifed("rsvp/promise/resolve", + ["../-internal","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var noop = __dependency1__.noop; + var _resolve = __dependency1__.resolve; + + /** + `RSVP.Promise.resolve` returns a promise that will become resolved with the + passed `value`. It is shorthand for the following: + + ```javascript + var promise = new RSVP.Promise(function(resolve, reject){ + resolve(1); + }); + + promise.then(function(value){ + // value === 1 + }); + ``` + + Instead of writing the above, your code now simply becomes the following: + + ```javascript + var promise = RSVP.Promise.resolve(1); + + promise.then(function(value){ + // value === 1 + }); + ``` + + @method resolve + @static + @param {Any} value value that the returned promise will be resolved with + @param {String} label optional string for identifying the returned promise. + Useful for tooling. + @return {Promise} a promise that will become fulfilled with the given + `value` + */ + __exports__["default"] = function resolve(object, label) { + /*jshint validthis:true */ + var Constructor = this; + + if (object && typeof object === 'object' && object.constructor === Constructor) { + return object; + } + + var promise = new Constructor(noop, label); + _resolve(promise, object); + return promise; + } + }); +enifed("rsvp/race", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + This is a convenient alias for `RSVP.Promise.race`. + + @method race + @static + @for RSVP + @param {Array} array Array of promises. + @param {String} label An optional label. This is useful + for tooling. + */ + __exports__["default"] = function race(array, label) { + return Promise.race(array, label); + } + }); +enifed("rsvp/reject", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + This is a convenient alias for `RSVP.Promise.reject`. + + @method reject + @static + @for RSVP + @param {Any} reason value that the returned promise will be rejected with. + @param {String} label optional string for identifying the returned promise. + Useful for tooling. + @return {Promise} a promise rejected with the given `reason`. + */ + __exports__["default"] = function reject(reason, label) { + return Promise.reject(reason, label); + } + }); +enifed("rsvp/resolve", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + This is a convenient alias for `RSVP.Promise.resolve`. + + @method resolve + @static + @for RSVP + @param {Any} value value that the returned promise will be resolved with + @param {String} label optional string for identifying the returned promise. + Useful for tooling. + @return {Promise} a promise that will become fulfilled with the given + `value` + */ + __exports__["default"] = function resolve(value, label) { + return Promise.resolve(value, label); + } + }); +enifed("rsvp/rethrow", + ["exports"], + function(__exports__) { + "use strict"; + /** + `RSVP.rethrow` will rethrow an error on the next turn of the JavaScript event + loop in order to aid debugging. + + Promises A+ specifies that any exceptions that occur with a promise must be + caught by the promises implementation and bubbled to the last handler. For + this reason, it is recommended that you always specify a second rejection + handler function to `then`. However, `RSVP.rethrow` will throw the exception + outside of the promise, so it bubbles up to your console if in the browser, + or domain/cause uncaught exception in Node. `rethrow` will also throw the + error again so the error can be handled by the promise per the spec. + + ```javascript + function throws(){ + throw new Error('Whoops!'); + } + + var promise = new RSVP.Promise(function(resolve, reject){ + throws(); + }); + + promise.catch(RSVP.rethrow).then(function(){ + // Code here doesn't run because the promise became rejected due to an + // error! + }, function (err){ + // handle the error here + }); + ``` + + The 'Whoops' error will be thrown on the next turn of the event loop + and you can watch for it in your console. You can also handle it using a + rejection handler given to `.then` or `.catch` on the returned promise. + + @method rethrow + @static + @for RSVP + @param {Error} reason reason the promise became rejected. + @throws Error + @static + */ + __exports__["default"] = function rethrow(reason) { + setTimeout(function() { + throw reason; + }); + throw reason; + } + }); +enifed("rsvp/utils", + ["exports"], + function(__exports__) { + "use strict"; + function objectOrFunction(x) { + return typeof x === 'function' || (typeof x === 'object' && x !== null); + } + + __exports__.objectOrFunction = objectOrFunction;function isFunction(x) { + return typeof x === 'function'; + } + + __exports__.isFunction = isFunction;function isMaybeThenable(x) { + return typeof x === 'object' && x !== null; + } + + __exports__.isMaybeThenable = isMaybeThenable;var _isArray; + if (!Array.isArray) { + _isArray = function (x) { + return Object.prototype.toString.call(x) === '[object Array]'; + }; + } else { + _isArray = Array.isArray; + } + + var isArray = _isArray; + __exports__.isArray = isArray; + // Date.now is not available in browsers < IE9 + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility + var now = Date.now || function() { return new Date().getTime(); }; + __exports__.now = now; + function F() { } + + var o_create = (Object.create || function (o) { + if (arguments.length > 1) { + throw new Error('Second argument not supported'); + } + if (typeof o !== 'object') { + throw new TypeError('Argument must be an object'); + } + F.prototype = o; + return new F(); + }); + __exports__.o_create = o_create; + }); +requireModule("ember"); + +})(); \ No newline at end of file diff --git a/bower_components/ember/ember.min.js b/bower_components/ember/ember.min.js new file mode 100644 index 0000000..9e5233a --- /dev/null +++ b/bower_components/ember/ember.min.js @@ -0,0 +1,12 @@ +!function(){var e,t,r,n,i;!function(){if(i=this.Ember=this.Ember||{},"undefined"==typeof i&&(i={}),"undefined"==typeof i.__loader){var a={},s={};e=function(e,t,r){a[e]={deps:t,callback:r}},n=r=t=function(e){function r(t){if("."!==t.charAt(0))return t;for(var r=t.split("/"),n=e.split("/").slice(0,-1),i=0,a=r.length;a>i;i++){var s=r[i];if(".."===s)n.pop();else{if("."===s)continue;n.push(s)}}return n.join("/")}if(s.hasOwnProperty(e))return s[e];if(s[e]={},!a[e])throw new Error("Could not find module "+e);for(var n,i=a[e],o=i.deps,u=i.callback,l=[],c=0,h=o.length;h>c;c++)l.push("exports"===o[c]?n={}:t(r(o[c])));var p=u.apply(this,l);return s[e]=n||p},n._eak_seen=a,i.__loader={define:e,require:r,registry:a}}else e=i.__loader.define,n=r=t=i.__loader.require}(),e("backburner",["backburner/utils","backburner/platform","backburner/binary-search","backburner/deferred-action-queues","exports"],function(e,t,r,n,i){"use strict";function a(e,t){this.queueNames=e,this.options=t||{},this.options.defaultQueue||(this.options.defaultQueue=e[0]),this.instanceStack=[],this._debouncees=[],this._throttlers=[],this._timers=[]}function s(e){return e.onError||e.onErrorTarget&&e.onErrorTarget[e.onErrorMethod]}function o(e){e.begin(),e._autorun=E.setTimeout(function(){e._autorun=null,e.end()})}function u(e,t,r){var n=g();(!e._laterTimer||tr;r+=2)e.schedule(e.options.defaultQueue,null,t[r])}),e._timers.length&&u(e,e._timers[0],e._timers[0]-i)}function c(e,t,r){return p(e,t,r)}function h(e,t,r){return p(e,t,r)}function p(e,t,r){for(var n,i=-1,a=0,s=r.length;s>a;a++)if(n=r[a],n[0]===e&&n[1]===t){i=a;break}return i}var m=e.each,f=e.isString,d=e.isFunction,v=e.isNumber,b=e.isCoercableNumber,y=e.wrapInTryCatch,g=e.now,_=t.needsIETryCatchFix,w=r["default"],x=n["default"],C=[].slice,O=[].pop,E=this;if(a.prototype={begin:function(){var e=this.options,t=e&&e.onBegin,r=this.currentInstance;r&&this.instanceStack.push(r),this.currentInstance=new x(this.queueNames,e),t&&t(this.currentInstance,r)},end:function(){var e=this.options,t=e&&e.onEnd,r=this.currentInstance,n=null,i=!1;try{r.flush()}finally{i||(i=!0,this.currentInstance=null,this.instanceStack.length&&(n=this.instanceStack.pop(),this.currentInstance=n),t&&t(r,n))}},run:function(e,t){var r=s(this.options);this.begin(),t||(t=e,e=null),f(t)&&(t=e[t]);var n=C.call(arguments,2),i=!1;if(r)try{return t.apply(e,n)}catch(a){r(a)}finally{i||(i=!0,this.end())}else try{return t.apply(e,n)}finally{i||(i=!0,this.end())}},defer:function(e,t,r){r||(r=t,t=null),f(r)&&(r=t[r]);var n,i=this.DEBUG?new Error:void 0,a=arguments.length;if(a>3){n=new Array(a-3);for(var s=3;a>s;s++)n[s-3]=arguments[s]}else n=void 0;return this.currentInstance||o(this),this.currentInstance.schedule(e,t,r,n,!1,i)},deferOnce:function(e,t,r){r||(r=t,t=null),f(r)&&(r=t[r]);var n,i=this.DEBUG?new Error:void 0,a=arguments.length;if(a>3){n=new Array(a-3);for(var s=3;a>s;s++)n[s-3]=arguments[s]}else n=void 0;return this.currentInstance||o(this),this.currentInstance.schedule(e,t,r,n,!0,i)},setTimeout:function(){function e(){if(y)try{i.apply(o,r)}catch(e){y(e)}else i.apply(o,r)}for(var t=arguments.length,r=new Array(t),n=0;t>n;n++)r[n]=arguments[n];var i,a,o,l,c,h,p=r.length;if(0!==p){if(1===p)i=r.shift(),a=0;else if(2===p)l=r[0],c=r[1],d(c)||d(l[c])?(o=r.shift(),i=r.shift(),a=0):b(c)?(i=r.shift(),a=r.shift()):(i=r.shift(),a=0);else{var m=r[r.length-1];a=b(m)?r.pop():0,l=r[0],h=r[1],d(h)||f(h)&&null!==l&&h in l?(o=r.shift(),i=r.shift()):i=r.shift()}var v=g()+parseInt(a,10);f(i)&&(i=o[i]);var y=s(this.options),_=w(v,this._timers);return this._timers.splice(_,0,v,e),u(this,v,a),e}},throttle:function(e,t){var r,n,i,a,s=this,o=arguments,u=O.call(o);return v(u)||f(u)?(r=u,u=!0):r=O.call(o),r=parseInt(r,10),i=h(e,t,this._throttlers),i>-1?this._throttlers[i]:(a=E.setTimeout(function(){u||s.run.apply(s,o);var r=h(e,t,s._throttlers);r>-1&&s._throttlers.splice(r,1)},r),u&&this.run.apply(this,o),n=[e,t,a],this._throttlers.push(n),n)},debounce:function(e,t){var r,n,i,a,s=this,o=arguments,u=O.call(o);return v(u)||f(u)?(r=u,u=!1):r=O.call(o),r=parseInt(r,10),n=c(e,t,this._debouncees),n>-1&&(i=this._debouncees[n],this._debouncees.splice(n,1),clearTimeout(i[2])),a=E.setTimeout(function(){u||s.run.apply(s,o);var r=c(e,t,s._debouncees);r>-1&&s._debouncees.splice(r,1)},r),u&&-1===n&&s.run.apply(s,o),i=[e,t,a],s._debouncees.push(i),i},cancelTimers:function(){var e=function(e){clearTimeout(e[2])};m(this._throttlers,e),this._throttlers=[],m(this._debouncees,e),this._debouncees=[],this._laterTimer&&(clearTimeout(this._laterTimer),this._laterTimer=null),this._timers=[],this._autorun&&(clearTimeout(this._autorun),this._autorun=null)},hasTimers:function(){return!!this._timers.length||!!this._debouncees.length||!!this._throttlers.length||this._autorun},cancel:function(e){var t=typeof e;if(e&&"object"===t&&e.queue&&e.method)return e.queue.cancel(e);if("function"!==t)return"[object Array]"===Object.prototype.toString.call(e)?this._cancelItem(h,this._throttlers,e)||this._cancelItem(c,this._debouncees,e):void 0;for(var r=0,n=this._timers.length;n>r;r+=2)if(this._timers[r+1]===e)return this._timers.splice(r,2),0===r&&(this._laterTimer&&(clearTimeout(this._laterTimer),this._laterTimer=null),this._timers.length>0&&u(this,this._timers[0],this._timers[0]-g())),!0},_cancelItem:function(e,t,r){var n,i;return r.length<3?!1:(i=e(r[0],r[1],t),i>-1&&(n=t[i],n[2]===r[2])?(t.splice(i,1),clearTimeout(r[2]),!0):!1)}},a.prototype.schedule=a.prototype.defer,a.prototype.scheduleOnce=a.prototype.deferOnce,a.prototype.later=a.prototype.setTimeout,_){var P=a.prototype.run;a.prototype.run=y(P);var A=a.prototype.end;a.prototype.end=y(A)}i["default"]=a}),e("backburner.umd",["./backburner"],function(t){"use strict";var r=t["default"];"function"==typeof e&&e.amd?e(function(){return r}):"undefined"!=typeof module&&module.exports?module.exports=r:"undefined"!=typeof this&&(this.Backburner=r)}),e("backburner/binary-search",["exports"],function(e){"use strict";e["default"]=function(e,t){for(var r,n,i=0,a=t.length-2;a>i;)n=(a-i)/2,r=i+n-n%2,e>=t[r]?i=r+2:a=r;return e>=t[i]?i+2:i}}),e("backburner/deferred-action-queues",["./utils","./queue","exports"],function(e,t,r){"use strict";function n(e,t){var r=this.queues={};this.queueNames=e=e||[],this.options=t,s(e,function(e){r[e]=new u(e,t[e],t)})}function i(e){throw new Error("You attempted to schedule an action in a queue ("+e+") that doesn't exist")}function a(e,t){for(var r,n,i=0,a=t;a>=i;i++)if(r=e.queueNames[i],n=e.queues[r],n._queue.length)return i;return-1}var s=e.each,o=e.isString,u=t["default"];n.prototype={schedule:function(e,t,r,n,a,s){var o=this.queues,u=o[e];return u||i(e),a?u.pushUnique(t,r,n,s):u.push(t,r,n,s)},invoke:function(e,t,r){r&&r.length>0?t.apply(e,r):t.call(e)},invokeWithOnError:function(e,t,r,n,i){try{r&&r.length>0?t.apply(e,r):t.call(e)}catch(a){n(a,i)}},flush:function(){for(var e,t,r,n,i=this.queues,s=this.queueNames,u=0,l=s.length,c=this.options,h=c.onError||c.onErrorTarget&&c.onErrorTarget[c.onErrorMethod],p=h?this.invokeWithOnError:this.invoke;l>u;){e=s[u],t=i[e],r=t._queueBeingFlushed=t._queue.slice(),t._queue=[],t.targetQueues=Object.create(null);var m,f,d,v,b=t.options,y=b&&b.before,g=b&&b.after,_=0,w=r.length;for(w&&y&&y();w>_;)m=r[_],f=r[_+1],d=r[_+2],v=r[_+3],o(f)&&(f=m[f]),f&&p(m,f,d,h,v),_+=4;t._queueBeingFlushed=null,w&&g&&g(),-1!==(n=a(this,u))?u=n:u++}}},r["default"]=n}),e("backburner/platform",["exports"],function(e){"use strict";var t=function(e,t){try{t()}catch(e){}return!!e}();e.needsIETryCatchFix=t}),e("backburner/queue",["exports"],function(e){"use strict";function t(e,t,r){this.name=e,this.globalOptions=r||{},this.options=t,this._queue=[],this.targetQueues=Object.create(null),this._queueBeingFlushed=void 0}t.prototype={push:function(e,t,r,n){var i=this._queue;return i.push(e,t,r,n),{queue:this,target:e,method:t}},pushUniqueWithoutGuid:function(e,t,r,n){for(var i=this._queue,a=0,s=i.length;s>a;a+=4){var o=i[a],u=i[a+1];if(o===e&&u===t)return i[a+2]=r,void(i[a+3]=n)}i.push(e,t,r,n)},targetQueue:function(e,t,r,n,i){for(var a=this._queue,s=0,o=e.length;o>s;s+=4){var u=e[s],l=e[s+1];if(u===r)return a[l+2]=n,void(a[l+3]=i)}e.push(r,a.push(t,r,n,i)-4)},pushUniqueWithGuid:function(e,t,r,n,i){var a=this.targetQueues[e];return a?this.targetQueue(a,t,r,n,i):this.targetQueues[e]=[r,this._queue.push(t,r,n,i)-4],{queue:this,target:t,method:r}},pushUnique:function(e,t,r,n){var i=(this._queue,this.globalOptions.GUID_KEY);if(e&&i){var a=e[i];if(a)return this.pushUniqueWithGuid(a,e,t,r,n)}return this.pushUniqueWithoutGuid(e,t,r,n),{queue:this,target:e,method:t}},flush:function(){var e,t,r,n,i,a=this._queue,s=this.globalOptions,o=this.options,u=o&&o.before,l=o&&o.after,c=s.onError||s.onErrorTarget&&s.onErrorTarget[s.onErrorMethod],h=a.length;for(this.targetQueues=Object.create(null),h&&u&&u(),i=0;h>i;i+=4)if(e=a[i],t=a[i+1],r=a[i+2],n=a[i+3],r&&r.length>0)if(c)try{t.apply(e,r)}catch(p){c(p)}else t.apply(e,r);else if(c)try{t.call(e)}catch(p){c(p)}else t.call(e);h&&l&&l(),a.length>h?(this._queue=a.slice(h),this.flush()):this._queue.length=0},cancel:function(e){var t,r,n,i,a=this._queue,s=e.target,o=e.method,u=this.globalOptions.GUID_KEY;if(u&&this.targetQueues&&s){var l=this.targetQueues[s[u]];if(l)for(n=0,i=l.length;i>n;n++)l[n]===o&&l.splice(n,1)}for(n=0,i=a.length;i>n;n+=4)if(t=a[n],r=a[n+1],t===s&&r===o)return a.splice(n,4),!0;if(a=this._queueBeingFlushed)for(n=0,i=a.length;i>n;n+=4)if(t=a[n],r=a[n+1],t===s&&r===o)return a[n+1]=null,!0}},e["default"]=t}),e("backburner/utils",["exports"],function(e){"use strict";function t(e,t){for(var r=0;r-1){try{if(e.existsSync(s)){var o,u=e.readFileSync(s,{encoding:"utf8"}),l=u.split("/").slice(-1)[0].trim(),c=u.split(" ")[1];if(c){var h=t.join(a,c.trim());o=e.readFileSync(h)}else o=l;i.push(o.slice(0,10))}}catch(p){console.error(p.stack)}return i.join(".")}return n}}),e("container",["container/container","exports"],function(e,t){"use strict";i.MODEL_FACTORY_INJECTIONS=!1,i.ENV&&"undefined"!=typeof i.ENV.MODEL_FACTORY_INJECTIONS&&(i.MODEL_FACTORY_INJECTIONS=!!i.ENV.MODEL_FACTORY_INJECTIONS);var r=e["default"];t["default"]=r}),e("container/container",["ember-metal/core","ember-metal/keys","ember-metal/dictionary","exports"],function(e,t,r,n){"use strict";function i(e){this.parent=e,this.children=[],this.resolver=e&&e.resolver||function(){},this.registry=C(e?e.registry:null),this.cache=C(e?e.cache:null),this.factoryCache=C(e?e.factoryCache:null),this.resolveCache=C(e?e.resolveCache:null),this.typeInjections=C(e?e.typeInjections:null),this.injections=C(null),this.normalizeCache=C(null),this.factoryTypeInjections=C(e?e.factoryTypeInjections:null),this.factoryInjections=C(null),this._options=C(e?e._options:null),this._typeOptions=C(e?e._typeOptions:null)}function a(e,t){var r=e.resolveCache[t];if(r)return r;var n=e.resolver(t)||e.registry[t];return e.resolveCache[t]=n,n}function s(e,t){return e.cache[t]?!0:!!e.resolve(t)}function o(e,t,r){if(r=r||{},e.cache[t]&&r.singleton!==!1)return e.cache[t];var n=d(e,t);return void 0!==n?(l(e,t)&&r.singleton!==!1&&(e.cache[t]=n),n):void 0}function u(e){throw new Error(e+" is not currently supported on child containers")}function l(e,t){var r=h(e,t,"singleton");return r!==!1}function c(e,t){var r={};if(!t)return r;for(var n,i,a=0,s=t.length;s>a;a++){if(n=t[a],i=o(e,n.fullName),void 0===i)throw new Error("Attempting to inject an unknown injection: `"+n.fullName+"`");r[n.property]=i}return r}function h(e,t,r){var n=e._options[t];if(n&&void 0!==n[r])return n[r];var i=t.split(":")[0];return n=e._typeOptions[i],n?n[r]:void 0}function p(e,t){var r=e.factoryCache;if(r[t])return r[t];var n=e.resolve(t);if(void 0!==n){var i=t.split(":")[0];if(!n||"function"!=typeof n.extend||!w.MODEL_FACTORY_INJECTIONS&&"model"===i)return r[t]=n,n;var a=m(e,t),s=f(e,t);s._toString=e.makeToString(n,t);var o=n.extend(a);return o.reopenClass(s),r[t]=o,o}}function m(e,t){var r=t.split(":"),n=r[0],i=[];return i=i.concat(e.typeInjections[n]||[]),i=i.concat(e.injections[t]||[]),i=c(e,i),i._debugContainerKey=t,i.container=e,i}function f(e,t){var r=t.split(":"),n=r[0],i=[];return i=i.concat(e.factoryTypeInjections[n]||[]),i=i.concat(e.factoryInjections[t]||[]),i=c(e,i),i._debugContainerKey=t,i}function d(e,t){var r=p(e,t);if(h(e,t,"instantiate")===!1)return r;if(r){if("function"!=typeof r.create)throw new Error("Failed to create an instance of '"+t+"'. Most likely an improperly defined class or an invalid module export.");return"function"==typeof r.extend?r.create():r.create(m(e,t))}}function v(e,t){for(var r,n,i=e.cache,a=x(i),s=0,o=a.length;o>s;s++)r=a[s],n=i[r],h(e,r,"instantiate")!==!1&&t(n)}function b(e){v(e,function(e){e.destroy()}),e.cache.dict=C(null)}function y(e,t,r,n){var i=e[t];i||(i=[],e[t]=i),i.push({property:r,fullName:n})}function g(e){if(!O.test(e))throw new TypeError("Invalid Fullname, expected: `type:name` got: "+e);return!0}function _(e,t,r,n){var i=e[t]=e[t]||[];i.push({property:r,fullName:n})}var w=e["default"],x=t["default"],C=r["default"];i.prototype={parent:null,children:null,resolver:null,registry:null,cache:null,typeInjections:null,injections:null,_options:null,_typeOptions:null,child:function(){var e=new i(this);return this.children.push(e),e},set:function(e,t,r){e[t]=r},register:function(e,t,r){if(void 0===t)throw new TypeError("Attempting to register an unknown factory: `"+e+"`");var n=this.normalize(e);if(n in this.cache)throw new Error("Cannot re-register: `"+e+"`, as it has already been looked up.");this.registry[n]=t,this._options[n]=r||{}},unregister:function(e){var t=this.normalize(e);delete this.registry[t],delete this.cache[t],delete this.factoryCache[t],delete this.resolveCache[t],delete this._options[t]},resolve:function(e){return a(this,this.normalize(e))},describe:function(e){return e},normalizeFullName:function(e){return e},normalize:function(e){return this.normalizeCache[e]||(this.normalizeCache[e]=this.normalizeFullName(e))},makeToString:function(e){return e.toString()},lookup:function(e,t){return o(this,this.normalize(e),t)},lookupFactory:function(e){return p(this,this.normalize(e))},has:function(e){return s(this,this.normalize(e))},optionsForType:function(e,t){this.parent&&u("optionsForType"),this._typeOptions[e]=t},options:function(e,t){this.optionsForType(e,t)},typeInjection:function(e,t,r){this.parent&&u("typeInjection");var n=r.split(":")[0];if(n===e)throw new Error("Cannot inject a `"+r+"` on other "+e+"(s). Register the `"+r+"` as a different type and perform the typeInjection.");y(this.typeInjections,e,t,r)},injection:function(e,t,r){this.parent&&u("injection"),g(r);var n=this.normalize(r);if(-1===e.indexOf(":"))return this.typeInjection(e,t,n);var i=this.normalize(e);if(this.cache[i])throw new Error("Attempted to register an injection for a type that has already been looked up. ('"+i+"', '"+t+"', '"+r+"')");_(this.injections,i,t,n)},factoryTypeInjection:function(e,t,r){this.parent&&u("factoryTypeInjection"),y(this.factoryTypeInjections,e,t,this.normalize(r))},factoryInjection:function(e,t,r){this.parent&&u("injection");var n=this.normalize(e),i=this.normalize(r);if(g(r),-1===e.indexOf(":"))return this.factoryTypeInjection(n,t,i);if(this.factoryCache[n])throw new Error("Attempted to register a factoryInjection for a type that has already been looked up. ('"+n+"', '"+t+"', '"+r+"')");_(this.factoryInjections,n,t,i)},destroy:function(){for(var e=0,t=this.children.length;t>e;e++)this.children[e].destroy();this.children=[],v(this,function(e){e.destroy()}),this.parent=void 0,this.isDestroyed=!0},reset:function(){for(var e=0,t=this.children.length;t>e;e++)b(this.children[e]);b(this)}};var O=/^[^:]+.+:[^:]+$/;n["default"]=i}),e("ember-application",["ember-metal/core","ember-runtime/system/lazy_load","ember-application/system/dag","ember-application/system/resolver","ember-application/system/application","ember-application/ext/controller"],function(e,t,r,n,i){"use strict";var a=e["default"],s=t.runLoadHooks,o=r["default"],u=n.Resolver,l=n["default"],c=i["default"];a.Application=c,a.DAG=o,a.Resolver=u,a.DefaultResolver=l,s("Ember.Application",c)}),e("ember-application/ext/controller",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/error","ember-metal/utils","ember-metal/computed","ember-runtime/mixins/controller","ember-routing/system/controller_for","exports"],function(e,t,r,n,i,a,s,o,u){"use strict";function l(e,t,r){var n,i,a,s=[];for(i=0,a=r.length;a>i;i++)n=r[i],-1===n.indexOf(":")&&(n="controller:"+n),t.has(n)||s.push(n);if(s.length)throw new h(p(e)+" needs [ "+s.join(", ")+" ] but "+(s.length>1?"they":"it")+" could not be found")}var c=(e["default"],t.get),h=(r.set,n["default"]),p=i.inspect,m=a.computed,f=s["default"],d=(i.meta,o["default"]),v=m(function(){var e=this;return{needs:c(e,"needs"),container:c(e,"container"),unknownProperty:function(t){var r,n,i,a=this.needs;for(n=0,i=a.length;i>n;n++)if(r=a[n],r===t)return this.container.lookup("controller:"+t);var s=p(e)+"#needs does not include `"+t+"`. To access the "+t+" controller from "+p(e)+", "+p(e)+" should have a `needs` property that is an array of the controllers it has access to.";throw new ReferenceError(s)},setUnknownProperty:function(t){throw new Error("You cannot overwrite the value of `controllers."+t+"` of "+p(e))}}});f.reopen({concatenatedProperties:["needs"],needs:[],init:function(){var e=c(this,"needs"),t=c(e,"length");t>0&&(this.container&&l(this,this.container,e),c(this,"controllers")),this._super.apply(this,arguments)},controllerFor:function(e){return d(c(this,"container"),e)},controllers:v}),u["default"]=f}),e("ember-application/system/application",["ember-metal","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/lazy_load","ember-application/system/dag","ember-runtime/system/namespace","ember-runtime/mixins/deferred","ember-application/system/resolver","ember-metal/platform","ember-metal/run_loop","ember-metal/utils","container/container","ember-runtime/controllers/controller","ember-metal/enumerable_utils","ember-runtime/controllers/object_controller","ember-runtime/controllers/array_controller","ember-handlebars/controls/select","ember-views/system/event_dispatcher","ember-views/system/jquery","ember-routing/system/route","ember-routing/system/router","ember-routing/location/hash_location","ember-routing/location/history_location","ember-routing/location/auto_location","ember-routing/location/none_location","ember-routing/system/cache","ember-metal/core","ember-handlebars-compiler","exports"],function(e,r,n,i,a,s,o,u,l,c,h,p,m,f,d,v,b,y,g,_,w,x,C,O,E,P,A,T,N){"use strict";function S(e){var t=[];for(var r in e)t.push(r);return t}function V(e){function t(e){return n.resolve(e)}e.get("resolver");var r=e.get("resolver")||e.get("Resolver")||z,n=r.create({namespace:e});return t.describe=function(e){return n.lookupDescription(e)},t.makeToString=function(e,t){return n.makeToString(e,t)},t.normalize=function(e){return n.normalize?n.normalize(e):e},t.__resolver__=n,t}var I,k=e["default"],D=r.get,j=n.set,M=i.runLoadHooks,R=a["default"],L=s["default"],H=o["default"],z=u["default"],q=l.create,F=c["default"],B=(h.canInvoke,p["default"]),U=m["default"],K=f["default"],W=d["default"],G=v["default"],Q=b["default"],$=y["default"],Y=g["default"],J=_["default"],Z=w["default"],X=x["default"],et=C["default"],tt=O["default"],rt=E["default"],nt=P["default"],it=A.K,at=T["default"],st=L.extend(H,{_suppressDeferredDeprecation:!0,rootElement:"body",eventDispatcher:null,customEvents:null,_readinessDeferrals:1,init:function(){if(this.$||(this.$=Y),this.__container__=this.buildContainer(),this.Router=this.defaultRouter(),this._super(),this.scheduleInitialize(),k.libraries.registerCoreLibrary("Handlebars"+(at.compile?"":"-runtime"),at.VERSION),k.libraries.registerCoreLibrary("jQuery",Y().jquery),k.LOG_VERSION){k.LOG_VERSION=!1;var e=K.map(k.libraries,function(e){return D(e,"name.length")}),t=Math.max.apply(this,e);k.libraries.each(function(e){new Array(t-e.length+1).join(" ")})}},buildContainer:function(){var e=this.__container__=st.buildContainer(this);return e},defaultRouter:function(){if(this.Router!==!1){var e=this.__container__;return this.Router&&(e.unregister("router:main"),e.register("router:main",this.Router)),e.lookupFactory("router:main")}},scheduleInitialize:function(){var e=this;!this.$||this.$.isReady?F.schedule("actions",e,"_initialize"):this.$().ready(function(){F(e,"_initialize")})},deferReadiness:function(){this._readinessDeferrals++},advanceReadiness:function(){this._readinessDeferrals--,0===this._readinessDeferrals&&F.once(this,this.didBecomeReady)},register:function(){var e=this.__container__;e.register.apply(e,arguments)},inject:function(){var e=this.__container__;e.injection.apply(e,arguments)},initialize:function(){},_initialize:function(){if(!this.isDestroyed){if(this.Router){var e=this.__container__;e.unregister("router:main"),e.register("router:main",this.Router)}return this.runInitializers(),M("application",this),this.advanceReadiness(),this}},reset:function(){function e(){var e=this.__container__.lookup("router:main");e.reset(),F(this.__container__,"destroy"),this.buildContainer(),F.schedule("actions",this,function(){this._initialize()})}this._readinessDeferrals=1,F.join(this,e)},runInitializers:function(){for(var e,t=D(this.constructor,"initializers"),r=S(t),n=this.__container__,i=new R,a=this,s=0;sa;a++)r(o[u[a]],t,n,i);t(e,i),i.pop()}}function n(){this.names=[],this.vertices=Object.create(null)}function i(e){this.name=e,this.incoming={},this.incomingNames=[],this.hasOutgoing=!1,this.value=null}var a=e["default"];n.prototype.add=function(e){if(!e)throw new Error("Can't add Vertex without name");if(void 0!==this.vertices[e])return this.vertices[e];var t=new i(e);return this.vertices[e]=t,this.names.push(e),t},n.prototype.map=function(e,t){this.add(e).value=t},n.prototype.addEdge=function(e,t){function n(e,r){if(e.name===t)throw new a("cycle detected: "+t+" <- "+r.join(" <- "))}if(e&&t&&e!==t){var i=this.add(e),s=this.add(t);s.incoming.hasOwnProperty(e)||(r(i,n),i.hasOutgoing=!0,s.incoming[e]=i,s.incomingNames.push(e))}},n.prototype.topsort=function(e){var t,n,i={},a=this.vertices,s=this.names,o=s.length;for(t=0;o>t;t++)n=a[s[t]],n.hasOutgoing||r(n,e,i)},n.prototype.addEdges=function(e,t,r,n){var i;if(this.map(e,t),r)if("string"==typeof r)this.addEdge(e,r);else for(i=0;i-1&&(i=i.replace(/\.(.)/g,function(e){return e.charAt(1).toUpperCase()})),n.indexOf("_")>-1&&(i=i.replace(/_(.)/g,function(e){return e.charAt(1).toUpperCase()})),r+":"+i}return e},resolve:function(e){var t,r=this.parseName(e),n=r.resolveMethodName;if(!r.name||!r.type)throw new TypeError("Invalid fullName: `"+e+"`, must be of the form `type:name` ");return this[n]&&(t=this[n](r)),t||(t=this.resolveOther(r)),r.root&&r.root.LOG_RESOLVER&&this._logLookup(t,r),t},parseName:function(e){return this._parseNameCache[e]||(this._parseNameCache[e]=this._parseName(e))},_parseName:function(e){var t=e.split(":"),r=t[0],n=t[1],i=n,a=c(this,"namespace"),s=a;if("template"!==r&&-1!==i.indexOf("/")){var o=i.split("/");i=o[o.length-1];var u=m(o.slice(0,-1).join("."));s=v.byName(u)}return{fullName:e,type:r,fullNameWithoutType:n,name:i,root:s,resolveMethodName:"resolve"+p(r)}},lookupDescription:function(e){var t=this.parseName(e);if("template"===t.type)return"template at "+t.fullNameWithoutType.replace(/\./g,"/");var r=t.root+"."+p(t.name);return"model"!==t.type&&(r+=p(t.type)),r},makeToString:function(e){return e.toString()},useRouterNaming:function(e){e.name=e.name.replace(/\./g,"_"),"basic"===e.name&&(e.name="")},resolveTemplate:function(e){var t=e.fullNameWithoutType.replace(/\./g,"/");return l.TEMPLATES[t]?l.TEMPLATES[t]:(t=f(t),l.TEMPLATES[t]?l.TEMPLATES[t]:void 0)},resolveView:function(e){return this.useRouterNaming(e),this.resolveOther(e)},resolveController:function(e){return this.useRouterNaming(e),this.resolveOther(e)},resolveRoute:function(e){return this.useRouterNaming(e),this.resolveOther(e)},resolveModel:function(e){var t=p(e.name),r=c(e.root,t);return r?r:void 0},resolveHelper:function(e){return this.resolveOther(e)||b.helpers[e.fullNameWithoutType]},resolveOther:function(e){var t=p(e.name)+p(e.type),r=c(e.root,t);return r?r:void 0},_logLookup:function(e,t){var r,n;r=e?"[✓]":"[ ]",n=t.fullName.length>60?".":new Array(60-t.fullName.length).join("."),h.info(r,t.fullName,n,this.lookupDescription(t.fullName))}})}),e("ember-extension-support",["ember-metal/core","ember-extension-support/data_adapter","ember-extension-support/container_debug_adapter"],function(e,t,r){"use strict";var n=e["default"],i=t["default"],a=r["default"];n.DataAdapter=i,n.ContainerDebugAdapter=a}),e("ember-extension-support/container_debug_adapter",["ember-metal/core","ember-runtime/system/native_array","ember-metal/utils","ember-runtime/system/string","ember-runtime/system/namespace","ember-runtime/system/object","exports"],function(e,t,r,n,i,a,s){"use strict";var o=e["default"],u=t.A,l=r.typeOf,c=n.dasherize,h=n.classify,p=i["default"],m=a["default"];s["default"]=m.extend({container:null,resolver:null,canCatalogEntriesByType:function(e){return"model"===e||"template"===e?!1:!0},catalogEntriesByType:function(e){var t=u(p.NAMESPACES),r=u(),n=new RegExp(h(e)+"$");return t.forEach(function(e){if(e!==o)for(var t in e)if(e.hasOwnProperty(t)&&n.test(t)){var i=e[t];"class"===l(i)&&r.push(c(t.replace(n,"")))}}),r}})}),e("ember-extension-support/data_adapter",["ember-metal/core","ember-metal/property_get","ember-metal/run_loop","ember-runtime/system/string","ember-runtime/system/namespace","ember-runtime/system/object","ember-runtime/system/native_array","ember-application/system/application","exports"],function(e,t,r,n,i,a,s,o,u){"use strict";var l=e["default"],c=t.get,h=r["default"],p=n.dasherize,m=i["default"],f=a["default"],d=s.A,v=o["default"];u["default"]=f.extend({init:function(){this._super(),this.releaseMethods=d()},container:null,containerDebugAdapter:void 0,attributeLimit:3,releaseMethods:d(),getFilters:function(){return d()},watchModelTypes:function(e,t){var r,n=this.getModelTypes(),i=this,a=d();r=n.map(function(e){var r=e.klass,n=i.wrapModelType(r,e.name);return a.push(i.observeModelType(r,t)),n}),e(r);var s=function(){a.forEach(function(e){e()}),i.releaseMethods.removeObject(s)};return this.releaseMethods.pushObject(s),s},_nameToClass:function(e){return"string"==typeof e&&(e=this.container.lookupFactory("model:"+e)),e},watchRecords:function(e,t,r,n){var i,a=this,s=d(),o=this.getRecords(e),u=function(e){r([e])},c=o.map(function(e){return s.push(a.observeRecord(e,u)),a.wrapRecord(e)}),h=function(e,r,i,o){for(var l=r;r+o>l;l++){var c=e.objectAt(l),h=a.wrapRecord(c);s.push(a.observeRecord(c,u)),t([h])}i&&n(r,i)},p={didChange:h,willChange:l.K};return o.addArrayObserver(a,p),i=function(){s.forEach(function(e){e()}),o.removeArrayObserver(a,p),a.releaseMethods.removeObject(i) +},t(c),this.releaseMethods.pushObject(i),i},willDestroy:function(){this._super(),this.releaseMethods.forEach(function(e){e()})},detect:function(){return!1},columnsForType:function(){return d()},observeModelType:function(e,t){var r=this,n=this.getRecords(e),i=function(){t([r.wrapModelType(e)])},a={didChange:function(){h.scheduleOnce("actions",this,i)},willChange:l.K};n.addArrayObserver(this,a);var s=function(){n.removeArrayObserver(r,a)};return s},wrapModelType:function(e,t){var r,n=this.getRecords(e);return r={name:t||e.toString(),count:c(n,"length"),columns:this.columnsForType(e),object:e}},getModelTypes:function(){var e,t=this,r=this.get("containerDebugAdapter");return e=r.canCatalogEntriesByType("model")?r.catalogEntriesByType("model"):this._getObjectsOnNamespaces(),e=d(e).map(function(e){return{klass:t._nameToClass(e),name:e}}),e=d(e).filter(function(e){return t.detect(e.klass)}),d(e)},_getObjectsOnNamespaces:function(){var e=d(m.NAMESPACES),t=d(),r=this;return e.forEach(function(e){for(var n in e)if(e.hasOwnProperty(n)&&r.detect(e[n])){var i=p(n);e instanceof v||!e.toString()||(i=e+"/"+i),t.push(i)}}),t},getRecords:function(){return d()},wrapRecord:function(e){var t={object:e};return t.columnValues=this.getRecordColumnValues(e),t.searchKeywords=this.getRecordKeywords(e),t.filterValues=this.getRecordFilterValues(e),t.color=this.getRecordColor(e),t},getRecordColumnValues:function(){return{}},getRecordKeywords:function(){return d()},getRecordFilterValues:function(){return{}},getRecordColor:function(){return null},observeRecord:function(){return function(){}}})}),e("ember-extension-support/initializers",[],function(){"use strict"}),e("ember-handlebars-compiler",["ember-metal/core","exports"],function(e,n){var i=e["default"];"undefined"==typeof i.assert&&(i.assert=function(){}),"undefined"==typeof i.FEATURES&&(i.FEATURES={isEnabled:function(){}});var a,s,o=Object.create||function(e){function t(){}return t.prototype=e,new t},u=i.imports&&i.imports.Handlebars||this&&this.Handlebars;u||"function"!=typeof r||(u=r("handlebars"));var l=i.Handlebars=o(u);l.helper=function(e,r){a||(a=t("ember-views/views/view")["default"]),s||(s=t("ember-views/views/component")["default"]),a.detect(r)?l.registerHelper(e,l.makeViewHelper(r)):l.registerBoundHelper.apply(null,arguments)},l.makeViewHelper=function(e){return function(t){return l.helpers.view.call(this,e,t)}},l.helpers=o(u.helpers),l.Compiler=function(){},u.Compiler&&(l.Compiler.prototype=o(u.Compiler.prototype)),l.Compiler.prototype.compiler=l.Compiler,l.JavaScriptCompiler=function(){},u.JavaScriptCompiler&&(l.JavaScriptCompiler.prototype=o(u.JavaScriptCompiler.prototype),l.JavaScriptCompiler.prototype.compiler=l.JavaScriptCompiler),l.JavaScriptCompiler.prototype.namespace="Ember.Handlebars",l.JavaScriptCompiler.prototype.initializeBuffer=function(){return"''"},l.JavaScriptCompiler.prototype.appendToBuffer=function(e){return"data.buffer.push("+e+");"};var c=/helpers\.(.*?)\)/,h=/helpers\['(.*?)'/,p=/(.*blockHelperMissing\.call\(.*)(stack[0-9]+)(,.*)/;l.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation=function(e){var t=e[e.length-1],r=(c.exec(t)||h.exec(t))[1],n=p.exec(t);e[e.length-1]=n[1]+"'"+r+"'"+n[3]};var m=l.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation,f=l.JavaScriptCompiler.prototype.blockValue;l.JavaScriptCompiler.prototype.blockValue=function(){f.apply(this,arguments),m(this.source)};var d=l.JavaScriptCompiler.prototype.ambiguousBlockValue;l.JavaScriptCompiler.prototype.ambiguousBlockValue=function(){d.apply(this,arguments),m(this.source)},l.Compiler.prototype.mustache=function(e){if(!e.params.length&&!e.hash){var t=new u.AST.IdNode([{part:"_triageMustache"}]);e.escaped||(e.hash=e.hash||new u.AST.HashNode([]),e.hash.pairs.push(["unescaped",new u.AST.StringNode("true")])),e=new u.AST.MustacheNode([t].concat([e.id]),e.hash,!e.escaped)}return u.Compiler.prototype.mustache.call(this,e)},l.precompile=function(e,t){var r=u.parse(e),n={knownHelpers:{action:!0,unbound:!0,"bind-attr":!0,template:!0,view:!0,_triageMustache:!0},data:!0,stringParams:!0};t=void 0===t?!0:t;var i=(new l.Compiler).compile(r,n);return(new l.JavaScriptCompiler).compile(i,n,void 0,t)},u.compile&&(l.compile=function(e){var t=u.parse(e),r={data:!0,stringParams:!0},n=(new l.Compiler).compile(t,r),i=(new l.JavaScriptCompiler).compile(n,r,void 0,!0),a=l.template(i);return a.isMethod=!1,a}),n["default"]=l}),e("ember-handlebars",["ember-handlebars-compiler","ember-metal/core","ember-runtime/system/lazy_load","ember-handlebars/loader","ember-handlebars/ext","ember-handlebars/string","ember-handlebars/helpers/shared","ember-handlebars/helpers/binding","ember-handlebars/helpers/collection","ember-handlebars/helpers/view","ember-handlebars/helpers/unbound","ember-handlebars/helpers/debug","ember-handlebars/helpers/each","ember-handlebars/helpers/template","ember-handlebars/helpers/partial","ember-handlebars/helpers/yield","ember-handlebars/helpers/loc","ember-handlebars/controls/checkbox","ember-handlebars/controls/select","ember-handlebars/controls/text_area","ember-handlebars/controls/text_field","ember-handlebars/controls/text_support","ember-handlebars/controls","ember-handlebars/component_lookup","ember-handlebars/views/handlebars_bound_view","ember-handlebars/views/metamorph_view","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m,f,d,v,b,y,g,_,w,x,C,O,E,P){"use strict";var A=e["default"],T=t["default"],N=r.runLoadHooks,S=n["default"],V=i.normalizePath,I=i.template,k=i.makeBoundHelper,D=i.registerBoundHelper,j=i.resolveHash,M=i.resolveParams,R=i.getEscaped,L=i.handlebarsGet,H=i.evaluateUnboundHelper,z=i.helperMissingHelper,q=i.blockHelperMissingHelper,F=s["default"],B=o.bind,U=o._triageMustacheHelper,K=o.resolveHelper,W=o.bindHelper,G=o.boundIfHelper,Q=o.unboundIfHelper,$=o.withHelper,Y=o.ifHelper,J=o.unlessHelper,Z=o.bindAttrHelper,X=o.bindAttrHelperDeprecated,et=o.bindClasses,tt=u["default"],rt=l.ViewHelper,nt=l.viewHelper,it=c["default"],at=h.logHelper,st=h.debuggerHelper,ot=p.EachView,ut=p.GroupedEach,lt=p.eachHelper,ct=m["default"],ht=f["default"],pt=d["default"],mt=v["default"],ft=b["default"],dt=y.Select,vt=y.SelectOption,bt=y.SelectOptgroup,yt=g["default"],gt=_["default"],_t=w["default"],wt=x.inputHelper,xt=x.textareaHelper,Ct=C["default"],Ot=O._HandlebarsBoundView,Et=O.SimpleHandlebarsView,Pt=E._wrapMap,At=E._SimpleMetamorphView,Tt=E._MetamorphView,Nt=E._Metamorph;A.bootstrap=S,A.template=I,A.makeBoundHelper=k,A.registerBoundHelper=D,A.resolveHash=j,A.resolveParams=M,A.resolveHelper=K,A.get=L,A.getEscaped=R,A.evaluateUnboundHelper=H,A.bind=B,A.bindClasses=et,A.EachView=ot,A.GroupedEach=ut,A.resolvePaths=F,A.ViewHelper=rt,A.normalizePath=V,T.Handlebars=A,T.ComponentLookup=Ct,T._SimpleHandlebarsView=Et,T._HandlebarsBoundView=Ot,T._SimpleMetamorphView=At,T._MetamorphView=Tt,T._Metamorph=Nt,T._metamorphWrapMap=Pt,T.TextSupport=_t,T.Checkbox=ft,T.Select=dt,T.SelectOption=vt,T.SelectOptgroup=bt,T.TextArea=yt,T.TextField=gt,T.TextSupport=_t,A.registerHelper("helperMissing",z),A.registerHelper("blockHelperMissing",q),A.registerHelper("bind",W),A.registerHelper("boundIf",G),A.registerHelper("_triageMustache",U),A.registerHelper("unboundIf",Q),A.registerHelper("with",$),A.registerHelper("if",Y),A.registerHelper("unless",J),A.registerHelper("bind-attr",Z),A.registerHelper("bindAttr",X),A.registerHelper("collection",tt),A.registerHelper("log",at),A.registerHelper("debugger",st),A.registerHelper("each",lt),A.registerHelper("loc",mt),A.registerHelper("partial",ht),A.registerHelper("template",ct),A.registerHelper("yield",pt),A.registerHelper("view",nt),A.registerHelper("unbound",it),A.registerHelper("input",wt),A.registerHelper("textarea",xt),N("Ember.Handlebars",A),P["default"]=A}),e("ember-handlebars/component_lookup",["ember-runtime/system/object","exports"],function(e,t){"use strict";var r=e["default"],n=r.extend({lookupFactory:function(e,t){t=t||this.container;var r="component:"+e,n="template:components/"+e,a=t&&t.has(n);a&&t.injection(r,"layout",n);var s=t.lookupFactory(r);return a||s?(s||(t.register(r,i.Component),s=t.lookupFactory(r)),s):void 0}});t["default"]=n}),e("ember-handlebars/controls",["ember-handlebars/controls/checkbox","ember-handlebars/controls/text_field","ember-handlebars/controls/text_area","ember-metal/core","ember-handlebars-compiler","ember-handlebars/ext","exports"],function(e,t,r,n,i,a,s){"use strict";function o(e,t,r){return"ID"===t.hashTypes[r]?f(e,t.hash[r],t):t.hash[r]}function u(e){var t=e.hash,r=e.hashTypes,n=o(this,e,"type"),i=t.on;return"checkbox"===n?(delete t.type,delete r.type,d.view.call(this,c,e)):(delete t.on,t.onEvent=i||"enter",d.view.call(this,h,e))}function l(e){e.hash,e.hashTypes;return d.view.call(this,p,e)}var c=e["default"],h=t["default"],p=r["default"],m=(n["default"],i["default"]),f=a.handlebarsGet,d=m.helpers;s.inputHelper=u,s.textareaHelper=l}),e("ember-handlebars/controls/checkbox",["ember-metal/property_get","ember-metal/property_set","ember-views/views/view","exports"],function(e,t,r,n){"use strict";var i=e.get,a=t.set,s=r["default"];n["default"]=s.extend({instrumentDisplay:'{{input type="checkbox"}}',classNames:["ember-checkbox"],tagName:"input",attributeBindings:["type","checked","indeterminate","disabled","tabindex","name","autofocus","required","form"],type:"checkbox",checked:!1,disabled:!1,indeterminate:!1,init:function(){this._super(),this.on("change",this,this._updateElementValue)},didInsertElement:function(){this._super(),i(this,"element").indeterminate=!!i(this,"indeterminate")},_updateElementValue:function(){a(this,"checked",this.$().prop("checked"))}})}),e("ember-handlebars/controls/select",["ember-handlebars-compiler","ember-metal/enumerable_utils","ember-metal/property_get","ember-metal/property_set","ember-views/views/view","ember-views/views/collection_view","ember-metal/utils","ember-metal/is_none","ember-metal/computed","ember-runtime/system/native_array","ember-metal/mixin","ember-metal/properties","exports"],function(e,t,r,n,a,s,o,u,l,c,h,p,m){"use strict";var f=e["default"],d=t.forEach,v=t.indexOf,b=t.indexesOf,y=t.replace,g=r.get,_=n.set,w=a["default"],x=s["default"],C=o.isArray,O=u["default"],E=l.computed,P=c.A,A=h.observer,T=p.defineProperty,N=(f.compile,w.extend({instrumentDisplay:"Ember.SelectOption",tagName:"option",attributeBindings:["value","selected"],defaultTemplate:function(e,t){t={data:t.data,hash:{}},f.helpers.bind.call(e,"view.label",t)},init:function(){this.labelPathDidChange(),this.valuePathDidChange(),this._super()},selected:E(function(){var e=g(this,"content"),t=g(this,"parentView.selection");return g(this,"parentView.multiple")?t&&v(t,e.valueOf())>-1:e==t}).property("content","parentView.selection"),labelPathDidChange:A("parentView.optionLabelPath",function(){var e=g(this,"parentView.optionLabelPath");e&&T(this,"label",E(function(){return g(this,e)}).property(e))}),valuePathDidChange:A("parentView.optionValuePath",function(){var e=g(this,"parentView.optionValuePath");e&&T(this,"value",E(function(){return g(this,e)}).property(e))})})),S=x.extend({instrumentDisplay:"Ember.SelectOptgroup",tagName:"optgroup",attributeBindings:["label"],selectionBinding:"parentView.selection",multipleBinding:"parentView.multiple",optionLabelPathBinding:"parentView.optionLabelPath",optionValuePathBinding:"parentView.optionValuePath",itemViewClassBinding:"parentView.optionView"}),V=w.extend({instrumentDisplay:"Ember.Select",tagName:"select",classNames:["ember-select"],defaultTemplate:i.Handlebars.template(function(e,t,r,n,a){function s(e,t){var n,i="";return t.buffer.push('"),i}function o(e,t){var n;n=r.each.call(e,"view.groupedContent",{hash:{},hashTypes:{},hashContexts:{},inverse:f.noop,fn:f.program(4,u,t),contexts:[e],types:["ID"],data:t}),t.buffer.push(n||0===n?n:"")}function u(e,t){t.buffer.push(m(r.view.call(e,"view.groupView",{hash:{content:"content",label:"label"},hashTypes:{content:"ID",label:"ID"},hashContexts:{content:e,label:e},contexts:[e],types:["ID"],data:t})))}function l(e,t){var n;n=r.each.call(e,"view.content",{hash:{},hashTypes:{},hashContexts:{},inverse:f.noop,fn:f.program(7,c,t),contexts:[e],types:["ID"],data:t}),t.buffer.push(n||0===n?n:"")}function c(e,t){t.buffer.push(m(r.view.call(e,"view.optionView",{hash:{content:""},hashTypes:{content:"ID"},hashContexts:{content:e},contexts:[e],types:["ID"],data:t})))}this.compilerInfo=[4,">= 1.0.0"],r=this.merge(r,i.Handlebars.helpers),a=a||{};var h,p="",m=this.escapeExpression,f=this;return h=r["if"].call(t,"view.prompt",{hash:{},hashTypes:{},hashContexts:{},inverse:f.noop,fn:f.program(1,s,a),contexts:[t],types:["ID"],data:a}),(h||0===h)&&a.buffer.push(h),h=r["if"].call(t,"view.optionGroupPath",{hash:{},hashTypes:{},hashContexts:{},inverse:f.program(6,l,a),fn:f.program(3,o,a),contexts:[t],types:["ID"],data:a}),(h||0===h)&&a.buffer.push(h),p}),attributeBindings:["multiple","disabled","tabindex","name","required","autofocus","form","size"],multiple:!1,disabled:!1,required:!1,content:null,selection:null,value:E(function(e,t){if(2===arguments.length)return t;var r=g(this,"optionValuePath").replace(/^content\.?/,"");return r?g(this,"selection."+r):g(this,"selection")}).property("selection"),prompt:null,optionLabelPath:"content",optionValuePath:"content",optionGroupPath:null,groupView:S,groupedContent:E(function(){var e=g(this,"optionGroupPath"),t=P(),r=g(this,"content")||[];return d(r,function(r){var n=g(r,e);g(t,"lastObject.label")!==n&&t.pushObject({label:n,content:P()}),g(t,"lastObject.content").push(r)}),t}).property("optionGroupPath","content.@each"),optionView:N,_change:function(){g(this,"multiple")?this._changeMultiple():this._changeSingle()},selectionDidChange:A("selection.@each",function(){var e=g(this,"selection");if(g(this,"multiple")){if(!C(e))return void _(this,"selection",P([e]));this._selectionDidChangeMultiple()}else this._selectionDidChangeSingle()}),valueDidChange:A("value",function(){var e,t=g(this,"content"),r=g(this,"value"),n=g(this,"optionValuePath").replace(/^content\.?/,""),i=n?g(this,"selection."+n):g(this,"selection");r!==i&&(e=t?t.find(function(e){return r===(n?g(e,n):e)}):null,this.set("selection",e))}),_triggerChange:function(){var e=g(this,"selection"),t=g(this,"value");O(e)||this.selectionDidChange(),O(t)||this.valueDidChange(),this._change()},_changeSingle:function(){var e=this.$()[0].selectedIndex,t=g(this,"content"),r=g(this,"prompt");if(t&&g(t,"length")){if(r&&0===e)return void _(this,"selection",null);r&&(e-=1),_(this,"selection",t.objectAt(e))}},_changeMultiple:function(){var e=this.$("option:selected"),t=g(this,"prompt"),r=t?1:0,n=g(this,"content"),i=g(this,"selection");if(n&&e){var a=e.map(function(){return this.index-r}).toArray(),s=n.objectsAt(a);C(i)?y(i,0,g(i,"length"),s):_(this,"selection",s)}},_selectionDidChangeSingle:function(){var e=this.get("element");if(e){var t=g(this,"content"),r=g(this,"selection"),n=t?v(t,r):-1,i=g(this,"prompt");i&&(n+=1),e&&(e.selectedIndex=n)}},_selectionDidChangeMultiple:function(){var e,t=g(this,"content"),r=g(this,"selection"),n=t?b(t,r):[-1],i=g(this,"prompt"),a=i?1:0,s=this.$("option");s&&s.each(function(){e=this.index>-1?this.index-a:-1,this.selected=v(n,e)>-1})},init:function(){this._super(),this.on("didInsertElement",this,this._triggerChange),this.on("change",this,this._change)}});m["default"]=V,m.Select=V,m.SelectOption=N,m.SelectOptgroup=S}),e("ember-handlebars/controls/text_area",["ember-metal/property_get","ember-views/views/component","ember-handlebars/controls/text_support","ember-metal/mixin","exports"],function(e,t,r,n,i){"use strict";var a=e.get,s=t["default"],o=r["default"],u=n.observer;i["default"]=s.extend(o,{instrumentDisplay:"{{textarea}}",classNames:["ember-text-area"],tagName:"textarea",attributeBindings:["rows","cols","name","selectionEnd","selectionStart","wrap","lang","dir"],rows:null,cols:null,_updateElementValue:u("value",function(){var e=a(this,"value"),t=this.$();t&&e!==t.val()&&t.val(e)}),init:function(){this._super(),this.on("didInsertElement",this,this._updateElementValue)}})}),e("ember-handlebars/controls/text_field",["ember-metal/property_get","ember-metal/property_set","ember-views/views/component","ember-handlebars/controls/text_support","exports"],function(e,t,r,n,i){"use strict";var a=(e.get,t.set,r["default"]),s=n["default"];i["default"]=a.extend(s,{instrumentDisplay:'{{input type="text"}}',classNames:["ember-text-field"],tagName:"input",attributeBindings:["type","value","size","pattern","name","min","max","accept","autocomplete","autosave","formaction","formenctype","formmethod","formnovalidate","formtarget","height","inputmode","list","multiple","step","lang","dir","width"],value:"",type:"text",size:null,pattern:null,min:null,max:null})}),e("ember-handlebars/controls/text_support",["ember-metal/property_get","ember-metal/property_set","ember-metal/mixin","ember-runtime/mixins/target_action_support","exports"],function(e,t,r,n,i){"use strict";function a(e,t,r){var n=s(t,e),i=s(t,"onEvent"),a=s(t,"value");(i===e||"keyPress"===i&&"key-press"===e)&&t.sendAction("action",a),t.sendAction(e,a),(n||i===e)&&(s(t,"bubbles")||r.stopPropagation())}var s=e.get,o=t.set,u=r.Mixin,l=n["default"],c=u.create(l,{value:"",attributeBindings:["placeholder","disabled","maxlength","tabindex","readonly","autofocus","form","selectionDirection","spellcheck","required","title","autocapitalize","autocorrect"],placeholder:null,disabled:!1,maxlength:null,init:function(){this._super(),this.on("focusOut",this,this._elementValueDidChange),this.on("change",this,this._elementValueDidChange),this.on("paste",this,this._elementValueDidChange),this.on("cut",this,this._elementValueDidChange),this.on("input",this,this._elementValueDidChange),this.on("keyUp",this,this.interpretKeyEvents)},action:null,onEvent:"enter",bubbles:!1,interpretKeyEvents:function(e){var t=c.KEY_EVENTS,r=t[e.keyCode];return this._elementValueDidChange(),r?this[r](e):void 0},_elementValueDidChange:function(){o(this,"value",this.$().val())},insertNewline:function(e){a("enter",this,e),a("insert-newline",this,e)},cancel:function(e){a("escape-press",this,e)},focusIn:function(e){a("focus-in",this,e)},focusOut:function(e){a("focus-out",this,e)},keyPress:function(e){a("key-press",this,e)}});c.KEY_EVENTS={13:"insertNewline",27:"cancel"},i["default"]=c}),e("ember-handlebars/ext",["ember-metal/core","ember-runtime/system/string","ember-handlebars-compiler","ember-metal/property_get","ember-metal/error","ember-metal/mixin","ember-views/views/view","ember-handlebars/views/metamorph_view","ember-metal/path_cache","ember-metal/is_empty","ember-metal/cache","exports"],function(e,r,n,i,a,s,o,u,l,c,h,p){"use strict";function m(e,t,r){var n,i,a=r&&r.keywords||{};return n=q.get(t),a.hasOwnProperty(n)&&(e=a[n],i=!0,t=t===n?"":t.substr(n.length+1)),{root:e,path:t,isKeyword:i}}function f(e,t,r){var n,i=r&&r.data,a=m(e,t,i);return e=a.root,t=a.path,(e||""===t)&&(n=k(e,t)),M(t)&&(void 0===n&&e!==N.lookup&&(e=N.lookup,n=k(e,t)),e===N.lookup||null===e),n}function d(e,t){return e.lookupFactory("view:"+t)}function v(e){var t;return M(e)?t=k(e):void 0}function b(e,t,r,n){var i,a,s;if(n&&(a=n.data,s=n.types&&n.types[0]),"string"==typeof t){if("STRING"===s&&r&&(i=d(r,t)),i||(i=v(t)),!i){if(a){var o=m(e,t,a);e=o.root,t=o.path}i=e&&k(e,t),i||(i=d(r,t))}}else i=t;return"string"==typeof i&&a&&a.view&&(i=b(a.view,i,r,{data:a,types:["ID"]})),i}function y(e,t,r){var n=f(e,t,r);return null===n||void 0===n?n="":n instanceof Handlebars.SafeString||(n=String(n)),r.hash.unescaped||(n=Handlebars.Utils.escapeExpression(n)),n}function g(e,t,r){for(var n,i,a=[],s=r.types,o=0,u=t.length;u>o;o++)n=t[o],i=s[o],a.push("ID"===i?f(e,n,r):n);return a}function _(e,t,r){var n,i={},a=r.hashTypes;for(var s in t)t.hasOwnProperty(s)&&(n=a[s],i[s]="ID"===n?f(e,t[s],r):t[s]);return i}function w(e){A||(A=t("ember-handlebars/helpers/binding").resolveHelper);var r,n="",i=arguments[arguments.length-1],a=A(i.data.view.container,e);if(a)return a.apply(this,L.call(arguments,1));throw r="%@ Handlebars error: Could not find property '%@' on object %@.",i.data&&(n=i.data.view),new D(S(r,[n,e,this]))}function x(e){A||(A=t("ember-handlebars/helpers/binding").resolveHelper);var r=arguments[arguments.length-1],n=A(r.data.view.container,e);return n?n.apply(this,L.call(arguments,1)):I.helperMissing.call(this,e)}function C(e){var t=L.call(arguments,1),r=O.apply(this,t);V.registerHelper(e,r)}function O(e){function r(){var t,r,i,a,s,o=L.call(arguments,0,-1),u=o.length,l=arguments[arguments.length-1],c=[],h=l.data,p=h.isUnbound?L.call(l.types,1):l.types,f=l.hash,d=l.hashTypes,v=h.view,b=l.contexts,y=b&&b.length?b[0]:this,g="",_=T.prototype.normalizedValue,w=f.boundOptions={};for(i in f)j.test(i)?w[i.slice(0,-7)]=f[i]:"ID"===d[i]&&(w[i]=f[i]);var x=[];for(h.properties=[],t=0;u>t;++t)if(h.properties.push(o[t]),"ID"===p[t]){var C=m(y,o[t],h);c.push(C),x.push(C)}else c.push(h.isUnbound?{path:o[t]}:null);if(h.isUnbound)return E(this,e,c,l);var O=new T(null,null,!l.hash.unescaped,l.data);O.normalizedValue=function(){var r,n=[];for(r in w)w.hasOwnProperty(r)&&(s=m(y,w[r],h),O.path=s.path,O.pathRoot=s.root,f[r]=_.call(O));for(t=0;u>t;++t)s=c[t],s?(O.path=s.path,O.pathRoot=s.root,n.push(_.call(O))):n.push(o[t]);return n.push(l),e.apply(y,n)},v.appendChild(O);for(a in w)w.hasOwnProperty(a)&&x.push(m(y,w[a],h));for(t=0,r=x.length;r>t;++t)s=x[t],v.registerObserver(s.root,s.path,O,O.rerender);if("ID"===p[0]&&0!==c.length){var P=c[0],A=P.root,N=P.path;R(N)||(g=N+".");for(var S=0,V=n.length;V>S;S++)v.registerObserver(A,g+n[S],O,O.rerender)}}T||(T=t("ember-handlebars/views/handlebars_bound_view").SimpleHandlebarsView);var n=L.call(arguments,1);return r._rawFunction=e,r}function E(e,t,r,n){var i,a,s,o,u,l=[],c=n.hash,h=c.boundOptions,p=L.call(n.types,1);for(u in h)h.hasOwnProperty(u)&&(c[u]=f(e,h[u],n));for(i=0,a=r.length;a>i;++i)s=r[i],o=p[i],l.push("ID"===o?f(s.root,s.path,n):s.path);return l.push(n),t.apply(e,l)}function P(e){var t=H(e);return t.isTop=!0,t}var A,T,N=e["default"],S=r.fmt,V=n["default"],I=V.helpers,k=i.get,D=a["default"],j=s.IS_BINDING,M=(o["default"],u._Metamorph,l.isGlobal),R=c["default"],L=[].slice,H=V.template,z=h["default"],q=new z(1e3,function(e){return e.split(".",1)[0]});p.getEscaped=y,p.resolveParams=g,p.resolveHash=_,p.helperMissingHelper=w,p.blockHelperMissingHelper=x,p.registerBoundHelper=C,p.template=P,p.normalizePath=m,p.makeBoundHelper=O,p.handlebarsGet=f,p.handlebarsGetView=b,p.evaluateUnboundHelper=E}),e("ember-handlebars/helpers/binding",["ember-metal/core","ember-handlebars-compiler","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-runtime/system/string","ember-metal/platform","ember-metal/is_none","ember-metal/enumerable_utils","ember-metal/array","ember-views/views/view","ember-metal/run_loop","ember-metal/observer","ember-metal/binding","ember-views/system/jquery","ember-handlebars/ext","ember-metal/keys","ember-metal/cache","ember-handlebars/views/handlebars_bound_view","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m,f,d,v,b,y,g){"use strict";function _(e){return!z(e)}function w(e,t,r,n,i,a){var s,o,u,l=t.data,c=t.fn,h=t.inverse,p=l.view,m=this||window;if(s=et(m,e,l),l.insideGroup){o=function(){for(;p._contextView;)p=p._contextView;B.once(p,"rerender")};var f,d,v=tt(m,e,t);v=i?i(v):v,d=r?m:v,n(v)?f=c:h&&(f=h),f(d,{data:t.data})}else{var b=Z,y={preserveContext:r,shouldDisplayFunc:n,valueNormalizerFunc:i,displayTemplate:c,inverseTemplate:h,path:e,pathRoot:m,previousContext:m,isEscaped:!t.hash.unescaped,templateData:t.data,templateHash:t.hash,helperName:t.helperName};t.isWithHelper&&(b=st);var g=p.createChildView(b,y);p.appendChild(g),o=function(){B.scheduleOnce("render",g,"rerenderIfNeeded")}}if("object"==typeof this&&""!==s.path&&(p.registerObserver(s.root,s.path,o),a))for(u=0;ua;a++){var s=e.objectAt(a);r.data.keywords[r.hash.keyword]=s,i(s,{data:n})}}},rerenderContainingView:function(){var e=this;T.scheduleOnce("render",this,function(){e.destroyed||e.containingView.rerender()})},destroy:function(){this.removeContentObservers(),this.content&&this.removeArrayObservers(),this.destroyed=!0}},b.EachView=M,b.GroupedEach=R,b.eachHelper=y}),e("ember-handlebars/helpers/loc",["ember-runtime/system/string","exports"],function(e,t){"use strict";var r=e.loc;t["default"]=r}),e("ember-handlebars/helpers/partial",["ember-metal/core","ember-metal/is_none","ember-handlebars/ext","ember-handlebars/helpers/binding","exports"],function(e,t,r,n,i){"use strict";function a(e){return!o(e)}function s(e,t,r){var n=t.split("/"),i=n[n.length-1];n[n.length-1]="_"+i;var a=r.data.view,s=n.join("/"),o=a.templateForName(s),u=!o&&a.templateForName(t);(o=o||u)(e,{data:r.data})}var o=(e["default"],t.isNone),u=r.handlebarsGet,l=n.bind;i["default"]=function(e,t){var r=t.contexts&&t.contexts.length?t.contexts[0]:this;return t.helperName=t.helperName||"partial","ID"===t.types[0]?(t.fn=function(t,r){var n=u(t,e,r);s(t,n,r)},l.call(r,e,t,!0,a)):void s(r,e,t)}}),e("ember-handlebars/helpers/shared",["ember-handlebars/ext","exports"],function(e,t){"use strict";var r=e.handlebarsGet;t["default"]=function(e){for(var t=[],n=e.contexts,i=e.roots,a=e.data,s=0,o=n.length;o>s;s++)t.push(r(i[s],n[s],{data:a}));return t}}),e("ember-handlebars/helpers/template",["ember-metal/core","ember-handlebars-compiler","exports"],function(e,t,r){"use strict";var n=(e["default"],t["default"]),i=n.helpers;r["default"]=function(e,t){return t.helperName=t.helperName||"template",i.partial.apply(this,arguments)}}),e("ember-handlebars/helpers/unbound",["ember-handlebars-compiler","ember-handlebars/helpers/binding","ember-handlebars/ext","exports"],function(e,t,r,n){"use strict";var i=e["default"],a=i.helpers,s=t.resolveHelper,o=r.handlebarsGet,u=[].slice;n["default"]=function(e,t){var r,n,i,l,c=arguments[arguments.length-1],h=c.data.view.container;return l=this,arguments.length>2?(c.data.isUnbound=!0,r=s(h,e)||a.helperMissing,i=r.apply(l,u.call(arguments,1)),delete c.data.isUnbound,i):(n=t.contexts&&t.contexts.length?t.contexts[0]:l,o(n,e,t))}}),e("ember-handlebars/helpers/view",["ember-metal/core","ember-runtime/system/object","ember-metal/property_get","ember-metal/property_set","ember-metal/mixin","ember-views/system/jquery","ember-views/views/view","ember-metal/binding","ember-metal/keys","ember-handlebars/ext","ember-runtime/system/string","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h){"use strict";function p(e,t){var r=t.hash,n=t.hashTypes;for(var i in r)if("ID"===n[i]){var a=r[i];d.test(i)||(r[i+"Binding"]=a,n[i+"Binding"]="STRING",delete r[i],delete n[i])}r.hasOwnProperty("idBinding")&&(r.id=_(e,r.idBinding,t),n.id="STRING",delete r.idBinding,delete n.idBinding)}function m(e,t){return e&&e.data&&e.data.isRenderData&&(t=e,e=t.data&&t.data.view&&t.data.view.container?t.data.view.container.lookupFactory("view:toplevel"):v),t.helperName=t.helperName||"view",x.helper(this,e,t)}var f=(e["default"],t["default"]),d=(r.get,n.set,i.IS_BINDING),v=(a["default"],s["default"]),b=o.isGlobalPath,y=u["default"],g=l.normalizePath,_=l.handlebarsGet,w=l.handlebarsGetView,x=(c["default"],f.create({propertiesFromHTMLOptions:function(e){var t=e.hash,r=e.data,n=t["class"],i={helperName:e.helperName||""};t.id&&(i.elementId=t.id),t.tag&&(i.tagName=t.tag),n&&(n=n.split(" "),i.classNames=n),t.classBinding&&(i.classNameBindings=t.classBinding.split(" ")),t.classNameBindings&&(void 0===i.classNameBindings&&(i.classNameBindings=[]),i.classNameBindings=i.classNameBindings.concat(t.classNameBindings.split(" "))),t.attributeBindings&&(i.attributeBindings=null);for(var a,s=y(t),o=0,u=s.length;u>o;o++){var l=s[o],c=d.test(l);"classNameBindings"!==l&&(i[l]=t[l]),c&&"string"==typeof i[l]&&(a=this.contextualizeBindingPath(t[l],r),a&&(i[l]=a))}if(i.classNameBindings)for(var h=0,p=i.classNameBindings.length;p>h;h++){var m=i.classNameBindings[h];if("string"==typeof m){var f=v._parsePropertyPath(m);""!==f.path&&(a=this.contextualizeBindingPath(f.path,r),a&&(i.classNameBindings[h]=a+f.classNames))}}return i},contextualizeBindingPath:function(e,t){var r=g(null,e,t);return r.isKeyword?"templateData.keywords."+e:b(e)?null:"this"===e||""===e?"_parentView.context":"_parentView.context."+e},helper:function(e,t,r){var n,i=r.data,a=r.fn;p(e,r);var s=this.container||i&&i.view&&i.view.container;n=w(e,t,s,r);var o=this.propertiesFromHTMLOptions(r,e),u=i.view;o.templateData=i;var l=n.proto();a&&(o.template=a),l.controller||l.controllerBinding||o.controller||o.controllerBinding||(o._context=e),u.appendChild(n,o)},instanceHelper:function(e,t,r){var n=r.data,i=r.fn;p(e,r);var a=this.propertiesFromHTMLOptions(r,e),s=n.view;a.templateData=n,i&&(a.template=i),t.controller||t.controllerBinding||a.controller||a.controllerBinding||(a._context=e),s.appendChild(t,a)}}));h.ViewHelper=x,h.viewHelper=m}),e("ember-handlebars/helpers/yield",["ember-metal/core","ember-metal/property_get","exports"],function(e,t,r){"use strict";var n=(e["default"],t.get);r["default"]=function(e){for(var t=e.data.view;t&&!n(t,"layout");)t=t._contextView?t._contextView:n(t,"_parentView");t._yield(this,e)}}),e("ember-handlebars/loader",["ember-handlebars/component_lookup","ember-views/system/jquery","ember-metal/error","ember-runtime/system/lazy_load","ember-handlebars-compiler","exports"],function(e,t,r,n,a,s){"use strict";function o(e){var t='script[type="text/x-handlebars"], script[type="text/x-raw-handlebars"]';h(t,e).each(function(){var e=h(this),t="text/x-raw-handlebars"===e.attr("type")?h.proxy(Handlebars.compile,Handlebars):h.proxy(f.compile,f),r=e.attr("data-template-name")||e.attr("id")||"application",n=t(e.html());if(void 0!==i.TEMPLATES[r])throw new p('Template named "'+r+'" already exists.');i.TEMPLATES[r]=n,e.remove()})}function u(){o(h(document))}function l(e){e.register("component-lookup:main",c)}var c=e["default"],h=t["default"],p=r["default"],m=n.onLoad,f=a["default"];m("Ember.Application",function(e){e.initializer({name:"domTemplates",initialize:u}),e.initializer({name:"registerComponentLookup",after:"domTemplates",initialize:l})}),s["default"]=o}),e("ember-handlebars/string",["ember-runtime/system/string","exports"],function(e,t){"use strict";function r(e){return new Handlebars.SafeString(e)}var n=e["default"];n.htmlSafe=r,(i.EXTEND_PROTOTYPES===!0||i.EXTEND_PROTOTYPES.String)&&(String.prototype.htmlSafe=function(){return r(this)}),t["default"]=r}),e("ember-handlebars/views/handlebars_bound_view",["ember-handlebars-compiler","ember-metal/core","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/merge","ember-metal/run_loop","ember-metal/computed","ember-views/views/view","ember-views/views/states","ember-handlebars/views/metamorph_view","ember-handlebars/ext","ember-metal/utils","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m){"use strict";function f(e,t,r,n){this.path=e,this.pathRoot=t,this.isEscaped=r,this.templateData=n,this[b.GUID_KEY]=N(),this._lastNormalizedValue=void 0,this.state="preRender",this.updateId=null,this._parentView=null,this.buffer=null,this._morph=null}var d=e["default"],v=d.SafeString,b=t["default"],y=b.K,g=r["default"],_=n.get,w=i.set,x=a["default"],C=s["default"],O=(o.computed,u["default"],l.cloneStates),E=l.states,P=E,A=c["default"],T=h.handlebarsGet,N=p.uuid;f.prototype={isVirtual:!0,isView:!0,destroy:function(){this.updateId&&(C.cancel(this.updateId),this.updateId=null),this._parentView&&this._parentView.removeChild(this),this.morph=null,this.state="destroyed"},propertyWillChange:y,propertyDidChange:y,normalizedValue:function(){var e,t,r=this.path,n=this.pathRoot,i=this.isEscaped;return""===r?e=n:(t=this.templateData,e=T(n,r,{data:t})),i||e instanceof v||(e=new v(e)),e},render:function(e){var t=this.normalizedValue();this._lastNormalizedValue=t,e._element=t},rerender:function(){switch(this.state){case"preRender":case"destroyed":break;case"inBuffer":throw new g("Something you did tried to replace an {{expression}} before it was inserted into the DOM.");case"hasElement":case"inDOM":this.updateId=C.scheduleOnce("render",this,"update")}return this},update:function(){this.updateId=null;var e=this.normalizedValue();e!==this._lastNormalizedValue&&(this._lastNormalizedValue=e,this._morph.update(e))},_transitionTo:function(e){this.state=e}},E=O(P),x(E._default,{rerenderIfNeeded:y}),x(E.inDOM,{rerenderIfNeeded:function(e){e.normalizedValue()!==e._lastNormalizedValue&&e.rerender()}});var S=A.extend({instrumentName:"boundHandlebars",_states:E,shouldDisplayFunc:null,preserveContext:!1,previousContext:null,displayTemplate:null,inverseTemplate:null,path:null,pathRoot:null,normalizedValue:function(){var e,t,r=_(this,"path"),n=_(this,"pathRoot"),i=_(this,"valueNormalizerFunc");return""===r?e=n:(t=_(this,"templateData"),e=T(n,r,{data:t})),i?i(e):e},rerenderIfNeeded:function(){this.currentState.rerenderIfNeeded(this)},render:function(e){var t=_(this,"isEscaped"),r=_(this,"shouldDisplayFunc"),n=_(this,"preserveContext"),i=_(this,"previousContext"),a=_(this,"inverseTemplate"),s=_(this,"displayTemplate"),o=this.normalizedValue();if(this._lastNormalizedValue=o,r(o))if(w(this,"template",s),n)w(this,"_context",i);else{if(!s)return null===o||void 0===o?o="":o instanceof v||(o=String(o)),t&&(o=Handlebars.Utils.escapeExpression(o)),void e.push(o);w(this,"_context",o)}else a?(w(this,"template",a),n?w(this,"_context",i):w(this,"_context",o)):w(this,"template",function(){return""});return this._super(e)}});m._HandlebarsBoundView=S,m.SimpleHandlebarsView=f}),e("ember-handlebars/views/metamorph_view",["ember-metal/core","ember-views/views/core_view","ember-views/views/view","ember-metal/mixin","ember-metal/run_loop","exports"],function(e,t,r,n,i,a){"use strict";var s=(e["default"],t["default"]),o=r["default"],u=n.Mixin,l=(i["default"],u.create({isVirtual:!0,tagName:"",instrumentName:"metamorph",init:function(){this._super()}}));a._Metamorph=l;var c=o.extend(l);a._MetamorphView=c;var h=s.extend(l);a._SimpleMetamorphView=h,a["default"]=o.extend(l)}),e("ember-metal-views",["ember-metal-views/renderer","exports"],function(e,t){"use strict";var r=e["default"];t.Renderer=r}),e("ember-metal-views/renderer",["morph","exports"],function(e,t){"use strict";function r(){this._uuid=0,this._views=new Array(2e3),this._queue=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],this._parents=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],this._elements=new Array(17),this._inserts={},this._dom=new u}function n(e,t,r){var n=this._views;n[0]=e;var i=void 0===r?-1:r,a=0,s=1,o=t?t._level+1:0,u=null==t?e:t._root,l=!!u._morph,c=this._queue;c[0]=0;for(var h,p,m,f=1,d=-1,v=this._parents,b=t||null,y=this._elements,g=null,_=null,w=0,x=e;f;){if(y[w]=g,x._morph||(x._morph=null),x._root=u,this.uuid(x),x._level=o+w,x._elementCreated&&this.remove(x,!1,!0),this.willCreateElement(x),_=x._morph&&x._morph.contextualElement,!_&&b&&b._childViewsMorph&&(_=b._childViewsMorph.contextualElement),!_&&x._didCreateElementWithoutMorph&&(_=document.body),g=this.createElement(x,_),v[w++]=d,d=a,b=x,c[f++]=a,h=this.childViews(x))for(p=h.length-1;p>=0;p--)m=h[p],a=s++,n[a]=m,c[f++]=a,x=m;for(a=c[--f],x=n[a];d===a;){if(w--,x._elementCreated=!0,this.didCreateElement(x),l&&this.willInsertElement(x),0===w){f--;break}d=v[w],b=-1===d?t:n[d],this.insertElement(x,b,g,-1),a=c[--f],x=n[a],g=y[w],y[w]=null}}for(this.insertElement(x,t,g,i),p=s-1;p>=0;p--)l&&(n[p]._elementInserted=!0,this.didInsertElement(n[p])),n[p]=null;return g}function i(e,t,r){var n=this.uuid(e);if(this._inserts[n]&&(this.cancelRender(this._inserts[n]),this._inserts[n]=void 0),e._elementCreated){var i,a,s,o,u,l,c,h=[],p=[],m=e._morph;for(h.push(e),i=0;il;l++)o.push(u[l]);for(i=0;il;l++)p.push(u[l]);for(m&&!r&&m.destroy(),i=0,a=h.length;a>i;i++)this.afterRemove(h[i],!1);for(i=0,a=p.length;a>i;i++)this.afterRemove(p[i],!0);r&&(e._morph=m)}}function a(e,t,r,n){null!==r&&void 0!==r&&(e._morph?e._morph.update(r):t&&(e._morph=-1===n?t._childViewsMorph.append(r):t._childViewsMorph.insert(n,r)))}function s(e){e._elementCreated&&this.willDestroyElement(e),e._elementInserted&&this.willRemoveElement(e)}function o(e,t){e._elementInserted=!1,e._morph=null,e._childViewsMorph=null,e._elementCreated&&(e._elementCreated=!1,this.didDestroyElement(e)),t&&this.destroyView(e)}var u=e.DOMHelper;r.prototype.uuid=function(e){return void 0===e._uuid&&(e._uuid=++this._uuid,e._renderer=this),e._uuid},r.prototype.scheduleInsert=function(e,t){if(e._morph||e._elementCreated)throw new Error("You cannot insert a View that has already been rendered");e._morph=t;var r=this.uuid(e);this._inserts[r]=this.scheduleRender(this,function(){this._inserts[r]=null,this.renderTree(e)})},r.prototype.appendTo=function(e,t){var r=this._dom.appendMorph(t);this.scheduleInsert(e,r)},r.prototype.replaceIn=function(e,t){var r=this._dom.createMorph(t,null,null);this.scheduleInsert(e,r)},r.prototype.remove=i,r.prototype.destroy=function(e){this.remove(e,!0)},r.prototype.renderTree=n,r.prototype.insertElement=a,r.prototype.beforeRemove=s,r.prototype.afterRemove=o;var l=function(){};r.prototype.willCreateElement=l,r.prototype.createElement=l,r.prototype.didCreateElement=l,r.prototype.willInsertElement=l,r.prototype.didInsertElement=l,r.prototype.willRemoveElement=l,r.prototype.willDestroyElement=l,r.prototype.didDestroyElement=l,r.prototype.destroyView=l,r.prototype.childViews=l,t["default"]=r}),e("ember-metal",["ember-metal/core","ember-metal/merge","ember-metal/instrumentation","ember-metal/utils","ember-metal/error","ember-metal/enumerable_utils","ember-metal/cache","ember-metal/platform","ember-metal/array","ember-metal/logger","ember-metal/property_get","ember-metal/events","ember-metal/observer_set","ember-metal/property_events","ember-metal/properties","ember-metal/property_set","ember-metal/map","ember-metal/get_properties","ember-metal/set_properties","ember-metal/watch_key","ember-metal/chains","ember-metal/watch_path","ember-metal/watching","ember-metal/expand_properties","ember-metal/computed","ember-metal/computed_macros","ember-metal/observer","ember-metal/mixin","ember-metal/binding","ember-metal/run_loop","ember-metal/libraries","ember-metal/is_none","ember-metal/is_empty","ember-metal/is_blank","ember-metal/is_present","ember-metal/keys","exports"],function(e,r,n,i,a,s,o,u,l,c,h,p,m,f,d,v,b,y,g,_,w,x,C,O,E,P,A,T,N,S,V,I,k,D,j,M,R){"use strict";var L=e["default"],H=r["default"],z=n.instrument,q=n.subscribe,F=n.unsubscribe,B=n.reset,U=i.generateGuid,K=i.GUID_KEY,W=i.guidFor,G=i.META_DESC,Q=i.EMPTY_META,$=i.meta,Y=i.getMeta,J=i.setMeta,Z=i.metaPath,X=i.inspect,et=i.typeOf,tt=i.tryCatchFinally,rt=i.isArray,nt=i.makeArray,it=i.canInvoke,at=i.tryInvoke,st=i.tryFinally,ot=i.wrap,ut=i.apply,lt=i.applyStr,ct=i.uuid,ht=a["default"],pt=s["default"],mt=o["default"],ft=u.create,dt=u.hasPropertyAccessors,vt=l.filter,bt=l.forEach,yt=l.indexOf,gt=l.map,_t=c["default"],wt=h.get,xt=h.getWithDefault,Ct=h.normalizeTuple,Ot=h._getPath,Et=p.on,Pt=p.addListener,At=p.removeListener,Tt=p.suspendListener,Nt=p.suspendListeners,St=p.sendEvent,Vt=p.hasListeners,It=p.watchedEvents,kt=p.listenersFor,Dt=p.listenersDiff,jt=p.listenersUnion,Mt=m["default"],Rt=f.propertyWillChange,Lt=f.propertyDidChange,Ht=f.overrideChains,zt=f.beginPropertyChanges,qt=f.endPropertyChanges,Ft=f.changeProperties,Bt=d.Descriptor,Ut=d.defineProperty,Kt=v.set,Wt=v.trySet,Gt=b.OrderedSet,Qt=b.Map,$t=b.MapWithDefault,Yt=y["default"],Jt=g["default"],Zt=_.watchKey,Xt=_.unwatchKey,er=w.flushPendingChains,tr=w.removeChainWatcher,rr=w.ChainNode,nr=w.finishChains,ir=x.watchPath,ar=x.unwatchPath,sr=C.watch,or=C.isWatching,ur=C.unwatch,lr=C.rewatch,cr=C.destroy,hr=O["default"],pr=E.ComputedProperty,mr=E.computed,fr=E.cacheFor,dr=A.addObserver,vr=A.observersFor,br=A.removeObserver,yr=A.addBeforeObserver,gr=A._suspendBeforeObserver,_r=A._suspendObserver,wr=A._suspendBeforeObservers,xr=A._suspendObservers,Cr=A.beforeObserversFor,Or=A.removeBeforeObserver,Er=T.IS_BINDING,Pr=T.mixin,Ar=T.Mixin,Tr=T.required,Nr=T.aliasMethod,Sr=T.observer,Vr=T.immediateObserver,Ir=T.beforeObserver,kr=N.Binding,Dr=N.isGlobalPath,jr=N.bind,Mr=N.oneWay,Rr=S["default"],Lr=V["default"],Hr=I.isNone,zr=I.none,qr=k.isEmpty,Fr=k.empty,Br=D["default"],Ur=j["default"],Kr=M["default"],Wr=L.Instrumentation={};Wr.instrument=z,Wr.subscribe=q,Wr.unsubscribe=F,Wr.reset=B,L.instrument=z,L.subscribe=q,L._Cache=mt,L.generateGuid=U,L.GUID_KEY=K,L.create=ft,L.keys=Kr,L.platform={defineProperty:Ut,hasPropertyAccessors:dt};var Gr=L.ArrayPolyfills={};Gr.map=gt,Gr.forEach=bt,Gr.filter=vt,Gr.indexOf=yt,L.Error=ht,L.guidFor=W,L.META_DESC=G,L.EMPTY_META=Q,L.meta=$,L.getMeta=Y,L.setMeta=J,L.metaPath=Z,L.inspect=X,L.typeOf=et,L.tryCatchFinally=tt,L.isArray=rt,L.makeArray=nt,L.canInvoke=it,L.tryInvoke=at,L.tryFinally=st,L.wrap=ot,L.apply=ut,L.applyStr=lt,L.uuid=ct,L.Logger=_t,L.get=wt,L.getWithDefault=xt,L.normalizeTuple=Ct,L._getPath=Ot,L.EnumerableUtils=pt,L.on=Et,L.addListener=Pt,L.removeListener=At,L._suspendListener=Tt,L._suspendListeners=Nt,L.sendEvent=St,L.hasListeners=Vt,L.watchedEvents=It,L.listenersFor=kt,L.listenersDiff=Dt,L.listenersUnion=jt,L._ObserverSet=Mt,L.propertyWillChange=Rt,L.propertyDidChange=Lt,L.overrideChains=Ht,L.beginPropertyChanges=zt,L.endPropertyChanges=qt,L.changeProperties=Ft,L.Descriptor=Bt,L.defineProperty=Ut,L.set=Kt,L.trySet=Wt,L.OrderedSet=Gt,L.Map=Qt,L.MapWithDefault=$t,L.getProperties=Yt,L.setProperties=Jt,L.watchKey=Zt,L.unwatchKey=Xt,L.flushPendingChains=er,L.removeChainWatcher=tr,L._ChainNode=rr,L.finishChains=nr,L.watchPath=ir,L.unwatchPath=ar,L.watch=sr,L.isWatching=or,L.unwatch=ur,L.rewatch=lr,L.destroy=cr,L.expandProperties=hr,L.ComputedProperty=pr,L.computed=mr,L.cacheFor=fr,L.addObserver=dr,L.observersFor=vr,L.removeObserver=br,L.addBeforeObserver=yr,L._suspendBeforeObserver=gr,L._suspendBeforeObservers=wr,L._suspendObserver=_r,L._suspendObservers=xr,L.beforeObserversFor=Cr,L.removeBeforeObserver=Or,L.IS_BINDING=Er,L.required=Tr,L.aliasMethod=Nr,L.observer=Sr,L.immediateObserver=Vr,L.beforeObserver=Ir,L.mixin=Pr,L.Mixin=Ar,L.oneWay=Mr,L.bind=jr,L.Binding=kr,L.isGlobalPath=Dr,L.run=Rr,L.libraries=Lr,L.libraries.registerCoreLibrary("Ember",L.VERSION),L.isNone=Hr,L.none=zr,L.isEmpty=qr,L.empty=Fr,L.isBlank=Br,L.isPresent=Ur,L.merge=H,L.onerror=null,L.__loader.registry["ember-debug"]&&t("ember-debug"),R["default"]=L}),e("ember-metal/alias",["ember-metal/property_get","ember-metal/property_set","ember-metal/error","ember-metal/properties","ember-metal/computed","ember-metal/platform","ember-metal/utils","ember-metal/dependent_keys","exports"],function(e,t,r,n,i,a,s,o,u){"use strict";function l(e){return new c(e)}function c(e){this.altKey=e,this._dependentKeys=[e]}function h(e,t){throw new d('Cannot set read-only property "'+t+'" on object: '+w(e))}function p(e,t,r){return b(e,t,null),f(e,t,r)}var m=e.get,f=t.set,d=r["default"],v=n.Descriptor,b=n.defineProperty,y=i.ComputedProperty,g=a.create,_=s.meta,w=s.inspect,x=o.addDependentKeys,C=o.removeDependentKeys;u.alias=l,u.AliasedProperty=c,c.prototype=g(v.prototype),c.prototype.get=function(e){return m(e,this.altKey)},c.prototype.set=function(e,t,r){return f(e,this.altKey,r)},c.prototype.willWatch=function(e,t){x(this,e,t,_(e))},c.prototype.didUnwatch=function(e,t){C(this,e,t,_(e))},c.prototype.setup=function(e,t){var r=_(e);r.watching[t]&&x(this,e,t,r)},c.prototype.teardown=function(e,t){var r=_(e);r.watching[t]&&C(this,e,t,r)},c.prototype.readOnly=function(){return this.set=h,this},c.prototype.oneWay=function(){return this.set=p,this},c.prototype._meta=void 0,c.prototype.meta=y.prototype.meta}),e("ember-metal/array",["exports"],function(e){"use strict";var t=Array.prototype,r=function(e){return e&&Function.prototype.toString.call(e).indexOf("[native code]")>-1},n=function(e,t){return r(e)?e:t},a=n(t.map,function(e){if(void 0===this||null===this||"function"!=typeof e)throw new TypeError;for(var t=Object(this),r=t.length>>>0,n=new Array(r),i=arguments[1],a=0;r>a;a++)a in t&&(n[a]=e.call(i,t[a],a,t));return n}),s=n(t.forEach,function(e){if(void 0===this||null===this||"function"!=typeof e)throw new TypeError;for(var t=Object(this),r=t.length>>>0,n=arguments[1],i=0;r>i;i++)i in t&&e.call(n,t[i],i,t)}),o=n(t.indexOf,function(e,t){null===t||void 0===t?t=0:0>t&&(t=Math.max(0,this.length+t));for(var r=t,n=this.length;n>r;r++)if(this[r]===e)return r;return-1}),u=n(t.lastIndexOf,function(e,t){var r,n=this.length;for(t=void 0===t?n-1:0>t?Math.ceil(t):Math.floor(t),0>t&&(t+=n),r=t;r>=0;r--)if(this[r]===e)return r;return-1}),l=n(t.filter,function(e,t){var r,n,i=[],a=this.length;for(r=0;a>r;r++)this.hasOwnProperty(r)&&(n=this[r],e.call(t,n,r,this)&&i.push(n));return i});i.SHIM_ES5&&(t.map=t.map||a,t.forEach=t.forEach||s,t.filter=t.filter||l,t.indexOf=t.indexOf||o,t.lastIndexOf=t.lastIndexOf||u),e.map=a,e.forEach=s,e.filter=l,e.indexOf=o,e.lastIndexOf=u}),e("ember-metal/binding",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/observer","ember-metal/run_loop","ember-metal/path_cache","exports"],function(e,t,r,n,i,a,s,o){"use strict";function u(e,t){return f(w(t)?m.lookup:e,t)}function l(e,t){this._direction=void 0,this._from=t,this._to=e,this._readyToSync=void 0,this._oneWay=void 0}function c(e,t){for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r])}function h(e,t,r){return new l(t,r).connect(e)}function p(e,t,r){return new l(t,r).oneWay().connect(e)}var m=e["default"],f=t.get,d=(r.set,r.trySet),v=n.guidFor,b=i.addObserver,y=i.removeObserver,g=i._suspendObserver,_=a["default"],w=s.isGlobal;m.LOG_BINDINGS=!1||!!m.ENV.LOG_BINDINGS,l.prototype={copy:function(){var e=new l(this._to,this._from);return this._oneWay&&(e._oneWay=!0),e},from:function(e){return this._from=e,this},to:function(e){return this._to=e,this},oneWay:function(){return this._oneWay=!0,this},toString:function(){var e=this._oneWay?"[oneWay]":"";return"Ember.Binding<"+v(this)+">("+this._from+" -> "+this._to+")"+e},connect:function(e){var t=this._from,r=this._to;return d(e,r,u(e,t)),b(e,t,this,this.fromDidChange),this._oneWay||b(e,r,this,this.toDidChange),this._readyToSync=!0,this},disconnect:function(e){var t=!this._oneWay;return y(e,this._from,this,this.fromDidChange),t&&y(e,this._to,this,this.toDidChange),this._readyToSync=!1,this},fromDidChange:function(e){this._scheduleSync(e,"fwd")},toDidChange:function(e){this._scheduleSync(e,"back")},_scheduleSync:function(e,t){var r=this._direction;void 0===r&&(_.schedule("sync",this,this._sync,e),this._direction=t),"back"===r&&"fwd"===t&&(this._direction="fwd")},_sync:function(e){var t=m.LOG_BINDINGS;if(!e.isDestroyed&&this._readyToSync){var r=this._direction,n=this._from,i=this._to;if(this._direction=void 0,"fwd"===r){var a=u(e,this._from);t&&m.Logger.log(" ",this.toString(),"->",a,e),this._oneWay?d(e,i,a):g(e,i,this,this.toDidChange,function(){d(e,i,a)})}else if("back"===r){var s=f(e,this._to);t&&m.Logger.log(" ",this.toString(),"<-",s,e),g(e,n,this,this.fromDidChange,function(){d(w(n)?m.lookup:e,n,s)})}}}},c(l,{from:function(e){var t=this;return new t(void 0,e)},to:function(e){var t=this;return new t(e,void 0)},oneWay:function(e,t){var r=this;return new r(void 0,e).oneWay(t)}}),o.bind=h,o.oneWay=p,o.Binding=l,o.isGlobalPath=w}),e("ember-metal/cache",["ember-metal/dictionary","exports"],function(e,t){"use strict";function r(e,t){this.store=n(null),this.size=0,this.misses=0,this.hits=0,this.limit=e,this.func=t}var n=e["default"];t["default"]=r;var i=function(){};r.prototype={set:function(e,t){return this.limit>this.size&&(this.size++,this.store[e]=void 0===t?i:t),t},get:function(e){var t=this.store[e];return void 0===t?(this.misses++,t=this.set(e,this.func(e))):t===i?(this.hits++,t=void 0):this.hits++,t},purge:function(){this.store=n(null),this.size=0,this.hits=0,this.misses=0}}}),e("ember-metal/chains",["ember-metal/core","ember-metal/property_get","ember-metal/utils","ember-metal/array","ember-metal/watch_key","exports"],function(e,t,r,n,i,a){"use strict";function s(e){return e.match(x)[0]}function o(){if(0!==C.length){var e=C;C=[],b.call(e,function(e){e[0].add(e[1])}),w("Watching an undefined global, Ember expects watched globals to be setup by the time the run loop is flushed, check for typos",0===C.length)}}function u(e,t,r){if(e&&"object"==typeof e){var n=_(e),i=n.chainWatchers;n.hasOwnProperty("chainWatchers")||(i=n.chainWatchers={}),i[t]||(i[t]=[]),i[t].push(r),y(e,t,n)}}function l(e,t,r){if(e&&"object"==typeof e){var n=e.__ember_meta__;if(!n||n.hasOwnProperty("chainWatchers")){var i=n&&n.chainWatchers;if(i&&i[t]){i=i[t];for(var a=0,s=i.length;s>a;a++)if(i[a]===r){i.splice(a,1);break}}g(e,t,n)}}}function c(e,t,r){this._parent=e,this._key=t,this._watching=void 0===r,this._value=r,this._paths={},this._watching&&(this._object=e.value(),this._object&&u(this._object,this._key,this)),this._parent&&"@each"===this._parent._key&&this.value()}function h(e,t){if(!e)return void 0;var r=e.__ember_meta__;if(r&&r.proto===e)return void 0;if("@each"===t)return f(e,t);var n=r&&r.descs[t];return n&&n._cacheable?t in r.cache?r.cache[t]:void 0:f(e,t)}function p(e){var t,r,n,i=e.__ember_meta__;if(i){if(r=i.chainWatchers)for(var a in r)if(r.hasOwnProperty(a)&&(n=r[a]))for(var s=0,o=n.length;o>s;s++)n[s].didChange(null);t=i.chains,t&&t.value()!==e&&(_(e).chains=t=t.copy(e))}}var m=e["default"],f=t.get,d=t.normalizeTuple,v=r.meta,b=n.forEach,y=i.watchKey,g=i.unwatchKey,_=v,w=m.warn,x=/^([^\.]+)/,C=[];a.flushPendingChains=o;var O=c.prototype;O.value=function(){if(void 0===this._value&&this._watching){var e=this._parent.value();this._value=h(e,this._key)}return this._value},O.destroy=function(){if(this._watching){var e=this._object;e&&l(e,this._key,this),this._watching=!1}},O.copy=function(e){var t,r=new c(null,null,e),n=this._paths;for(t in n)n[t]<=0||r.add(t);return r},O.add=function(e){var t,r,n,i,a;if(a=this._paths,a[e]=(a[e]||0)+1,t=this.value(),r=d(t,e),r[0]&&r[0]===t)e=r[1],n=s(e),e=e.slice(n.length+1);else{if(!r[0])return C.push([this,e]),void(r.length=0);i=r[0],n=e.slice(0,0-(r[1].length+1)),e=r[1]}r.length=0,this.chain(n,e,i)},O.remove=function(e){var t,r,n,i,a;a=this._paths,a[e]>0&&a[e]--,t=this.value(),r=d(t,e),r[0]===t?(e=r[1],n=s(e),e=e.slice(n.length+1)):(i=r[0],n=e.slice(0,0-(r[1].length+1)),e=r[1]),r.length=0,this.unchain(n,e)},O.count=0,O.chain=function(e,t,r){var n,i=this._chains;i||(i=this._chains={}),n=i[e],n||(n=i[e]=new c(this,e,r)),n.count++,t&&(e=s(t),t=t.slice(e.length+1),n.chain(e,t))},O.unchain=function(e,t){var r=this._chains,n=r[e];t&&t.length>1&&(e=s(t),t=t.slice(e.length+1),n.unchain(e,t)),n.count--,n.count<=0&&(delete r[n._key],n.destroy())},O.willChange=function(e){var t=this._chains;if(t)for(var r in t)t.hasOwnProperty(r)&&t[r].willChange(e);this._parent&&this._parent.chainWillChange(this,this._key,1,e)},O.chainWillChange=function(e,t,r,n){this._key&&(t=this._key+"."+t),this._parent?this._parent.chainWillChange(this,t,r+1,n):(r>1&&n.push(this.value(),t),t="this."+t,this._paths[t]>0&&n.push(this.value(),t))},O.chainDidChange=function(e,t,r,n){this._key&&(t=this._key+"."+t),this._parent?this._parent.chainDidChange(this,t,r+1,n):(r>1&&n.push(this.value(),t),t="this."+t,this._paths[t]>0&&n.push(this.value(),t))},O.didChange=function(e){if(this._watching){var t=this._parent.value();t!==this._object&&(l(this._object,this._key,this),this._object=t,u(t,this._key,this)),this._value=void 0,this._parent&&"@each"===this._parent._key&&this.value()}var r=this._chains;if(r)for(var n in r)r.hasOwnProperty(n)&&r[n].didChange(e);null!==e&&this._parent&&this._parent.chainDidChange(this,this._key,1,e)},a.finishChains=p,a.removeChainWatcher=l,a.ChainNode=c}),e("ember-metal/computed",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/expand_properties","ember-metal/error","ember-metal/properties","ember-metal/property_events","ember-metal/dependent_keys","exports"],function(e,t,r,n,i,a,s,o,u,l){"use strict";function c(){}function h(e,t){e.__ember_arity__=e.length,this.func=e,this._cacheable=t&&void 0!==t.cacheable?t.cacheable:!0,this._dependentKeys=t&&t.dependentKeys,this._readOnly=t&&(void 0!==t.readOnly||!!t.readOnly)||!1}function p(e){for(var t=0,r=e.length;r>t;t++)e[t].didChange(null)}function m(e){var t;if(arguments.length>1&&(t=A.call(arguments),e=t.pop()),"function"!=typeof e)throw new g("Computed Property declared without a property function");var r=new h(e);return t&&r.property.apply(r,t),r}function f(e,t){var r=e.__ember_meta__,n=r&&r.cache,i=n&&n[t];return i===c?void 0:i}var d=(e["default"],t.get,r.set),v=n.meta,b=n.inspect,y=i["default"],g=a["default"],_=s.Descriptor,w=s.defineProperty,x=o.propertyWillChange,C=o.propertyDidChange,O=u.addDependentKeys,E=u.removeDependentKeys,P=v,A=[].slice;h.prototype=new _;var T=h.prototype;T._dependentKeys=void 0,T._suspended=void 0,T._meta=void 0,T.cacheable=function(e){return this._cacheable=e!==!1,this},T["volatile"]=function(){return this.cacheable(!1)},T.readOnly=function(e){return this._readOnly=void 0===e||!!e,this},T.property=function(){var e,t=function(t){e.push(t) +};e=[];for(var r=0,n=arguments.length;n>r;r++)y(arguments[r],t);return this._dependentKeys=e,this},T.meta=function(e){return 0===arguments.length?this._meta||{}:(this._meta=e,this)},T.didChange=function(e,t){if(this._cacheable&&this._suspended!==e){var r=P(e);void 0!==r.cache[t]&&(r.cache[t]=void 0,E(this,e,t,r))}},T.get=function(e,t){var r,n,i,a;if(this._cacheable){i=P(e),n=i.cache;var s=n[t];if(s===c)return void 0;if(void 0!==s)return s;r=this.func.call(e,t),n[t]=void 0===r?c:r,a=i.chainWatchers&&i.chainWatchers[t],a&&p(a),O(this,e,t,i)}else r=this.func.call(e,t);return r},T.set=function(e,t,r){var n=this._suspended;this._suspended=e;try{this._set(e,t,r)}finally{this._suspended=n}},T._set=function(e,t,r){var n,i,a,s=this._cacheable,o=this.func,u=P(e,s),l=u.cache,h=!1;if(this._readOnly)throw new g('Cannot set read-only property "'+t+'" on object: '+b(e));if(s&&void 0!==l[t]&&(l[t]!==c&&(i=l[t]),h=!0),n=o.wrappedFunction?o.wrappedFunction.__ember_arity__:o.__ember_arity__,3===n)a=o.call(e,t,r,i);else{if(2!==n)return w(e,t,null,i),void d(e,t,r);a=o.call(e,t,r)}if(!h||i!==a){var p=u.watching[t];return p&&x(e,t),h&&(l[t]=void 0),s&&(h||O(this,e,t,u),l[t]=void 0===a?c:a),p&&C(e,t),a}},T.teardown=function(e,t){var r=P(e);return t in r.cache&&E(this,e,t,r),this._cacheable&&delete r.cache[t],null},f.set=function(e,t,r){e[t]=void 0===r?c:r},f.get=function(e,t){var r=e[t];return r===c?void 0:r},f.remove=function(e,t){e[t]=void 0},l.ComputedProperty=h,l.computed=m,l.cacheFor=f}),e("ember-metal/computed_macros",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/computed","ember-metal/is_empty","ember-metal/is_none","ember-metal/alias"],function(e,t,r,n,i,a,s){"use strict";function o(e,t){for(var r={},n=0;nt}),u("gte",function(e,t){return c(this,e)>=t}),u("lt",function(e,t){return c(this,e)1?(h(this,e,r),r):c(this,e)})}}),e("ember-metal/core",["exports"],function(e){"use strict";"undefined"==typeof i&&(i={});{var t=(i.imports=i.imports||this,i.exports=i.exports||this);i.lookup=i.lookup||this}t.Em=t.Ember=i,i.isNamespace=!0,i.toString=function(){return"Ember"},i.VERSION="1.8.0",i.ENV||(i.ENV="undefined"!=typeof EmberENV?EmberENV:"undefined"!=typeof ENV?ENV:{}),i.config=i.config||{},"undefined"==typeof i.ENV.DISABLE_RANGE_API&&(i.ENV.DISABLE_RANGE_API=!0),"undefined"==typeof MetamorphENV&&(t.MetamorphENV={}),MetamorphENV.DISABLE_RANGE_API=i.ENV.DISABLE_RANGE_API,i.FEATURES=i.ENV.FEATURES||{},i.FEATURES.isEnabled=function(e){var t=i.FEATURES[e];return i.ENV.ENABLE_ALL_FEATURES?!0:t===!0||t===!1||void 0===t?t:i.ENV.ENABLE_OPTIONAL_FEATURES?!0:!1},i.EXTEND_PROTOTYPES=i.ENV.EXTEND_PROTOTYPES,"undefined"==typeof i.EXTEND_PROTOTYPES&&(i.EXTEND_PROTOTYPES=!0),i.LOG_STACKTRACE_ON_DEPRECATION=i.ENV.LOG_STACKTRACE_ON_DEPRECATION!==!1,i.SHIM_ES5=i.ENV.SHIM_ES5===!1?!1:i.EXTEND_PROTOTYPES,i.LOG_VERSION=i.ENV.LOG_VERSION===!1?!1:!0;var r=function(){return this},r=r;e.K=r,i.K=r,"undefined"==typeof i.assert&&(i.assert=i.K),"undefined"==typeof i.warn&&(i.warn=i.K),"undefined"==typeof i.debug&&(i.debug=i.K),"undefined"==typeof i.runInDebug&&(i.runInDebug=i.K),"undefined"==typeof i.deprecate&&(i.deprecate=i.K),"undefined"==typeof i.deprecateFunc&&(i.deprecateFunc=function(e,t){return t}),e["default"]=i}),e("ember-metal/dependent_keys",["ember-metal/platform","ember-metal/watching","exports"],function(e,t,r){"use strict";function n(e,t){var r=e[t];return r?e.hasOwnProperty(t)||(r=e[t]=c(r)):r=e[t]={},r}function i(e){return n(e,"deps")}function a(e,t,r,a){var s,o,l,c,h,p=e._dependentKeys;if(p)for(s=i(a),o=0,l=p.length;l>o;o++)c=p[o],h=n(s,c),h[r]=(h[r]||0)+1,u(t,c,a)}function s(e,t,r,a){var s,o,u,c,h,p=e._dependentKeys;if(p)for(s=i(a),o=0,u=p.length;u>o;o++)c=p[o],h=n(s,c),h[r]=(h[r]||0)-1,l(t,c,a)}var o=e.create,u=t.watch,l=t.unwatch,c=o;r.addDependentKeys=a,r.removeDependentKeys=s}),e("ember-metal/deprecate_property",["ember-metal/core","ember-metal/platform","ember-metal/properties","ember-metal/property_get","ember-metal/property_set","exports"],function(e,t,r,n,i,a){"use strict";function s(e,t,r){function n(){}o&&u(e,t,{configurable:!0,enumerable:!1,set:function(e){n(),c(this,r,e)},get:function(){return n(),l(this,r)}})}var o=(e["default"],t.hasPropertyAccessors),u=r.defineProperty,l=n.get,c=i.set;a.deprecateProperty=s}),e("ember-metal/dictionary",["ember-metal/platform","exports"],function(e,t){"use strict";var r=e.create;t["default"]=function(e){var t=r(e);return t._dict=null,delete t._dict,t}}),e("ember-metal/enumerable_utils",["ember-metal/array","exports"],function(e,t){"use strict";function r(e,t,r){return e.map?e.map(t,r):d.call(e,t,r)}function n(e,t,r){return e.forEach?e.forEach(t,r):m.call(e,t,r)}function i(e,t,r){return e.filter?e.filter(t,r):p.call(e,t,r)}function a(e,t,r){return e.indexOf?e.indexOf(t,r):f.call(e,t,r)}function s(e,t){return void 0===t?[]:r(t,function(t){return a(e,t)})}function o(e,t){var r=a(e,t);-1===r&&e.push(t)}function u(e,t){var r=a(e,t);-1!==r&&e.splice(r,1)}function l(e,t,r,n){for(var i,a,s=[].concat(n),o=[],u=6e4,l=t,c=r;s.length;)i=c>u?u:c,0>=i&&(i=0),a=s.splice(0,u),a=[l,i].concat(a),l+=u,c-=i,o=o.concat(v.apply(e,a));return o}function c(e,t,r,n){return e.replace?e.replace(t,r,n):l(e,t,r,n)}function h(e,t){var r=[];return n(e,function(e){a(t,e)>=0&&r.push(e)}),r}var p=e.filter,m=e.forEach,f=e.indexOf,d=e.map,v=Array.prototype.splice;t.map=r,t.forEach=n,t.filter=i,t.indexOf=a,t.indexesOf=s,t.addObject=o,t.removeObject=u,t._replace=l,t.replace=c,t.intersection=h,t["default"]={_replace:l,addObject:o,filter:i,forEach:n,indexOf:a,indexesOf:s,intersection:h,map:r,removeObject:u,replace:c}}),e("ember-metal/error",["ember-metal/platform","exports"],function(e,t){"use strict";function r(){var e=Error.apply(this,arguments);Error.captureStackTrace&&Error.captureStackTrace(this,i.Error);for(var t=0;t=0;i-=3)if(t===e[i]&&r===e[i+1]){n=i;break}return n}function a(e,t){var r,n=O(e,!0);return n.listeners||(n.listeners={}),n.hasOwnProperty("listeners")||(n.listeners=x(n.listeners)),r=n.listeners[t],r&&!n.listeners.hasOwnProperty(t)?r=n.listeners[t]=n.listeners[t].slice():r||(r=n.listeners[t]=[]),r}function s(e,t,r){var n=e.__ember_meta__,a=n&&n.listeners&&n.listeners[t];if(a)for(var s=a.length-3;s>=0;s-=3){var o=a[s],u=a[s+1],l=a[s+2],c=i(r,o,u);-1===c&&r.push(o,u,l)}}function o(e,t,r){var n=e.__ember_meta__,a=n&&n.listeners&&n.listeners[t],s=[];if(a){for(var o=a.length-3;o>=0;o-=3){var u=a[o],l=a[o+1],c=a[o+2],h=i(r,u,l);-1===h&&(r.push(u,l,c),s.push(u,l,c))}return s}}function u(e,t,r,n,s){n||"function"!=typeof r||(n=r,r=null);var o=a(e,t),u=i(o,r,n),l=0;s&&(l|=E),-1===u&&(o.push(r,n,l),"function"==typeof e.didAddListener&&e.didAddListener(t,r,n))}function l(e,t,r,n){function s(r,n){var s=a(e,t),o=i(s,r,n);-1!==o&&(s.splice(o,3),"function"==typeof e.didRemoveListener&&e.didRemoveListener(t,r,n))}if(n||"function"!=typeof r||(n=r,r=null),n)s(r,n);else{var o=e.__ember_meta__,u=o&&o.listeners&&o.listeners[t];if(!u)return;for(var l=u.length-3;l>=0;l-=3)s(u[l],u[l+1])}}function c(e,t,r,n,s){function o(){return s.call(r)}function u(){-1!==c&&(l[c+2]&=~P)}n||"function"!=typeof r||(n=r,r=null);var l=a(e,t),c=i(l,r,n);return-1!==c&&(l[c+2]|=P),g(o,u)}function h(e,t,r,n,s){function o(){return s.call(r)}function u(){for(var e=0,t=m.length;t>e;e++){var r=m[e];f[e][r+2]&=~P}}n||"function"!=typeof r||(n=r,r=null);var l,c,h,p,m=[],f=[];for(h=0,p=t.length;p>h;h++){l=t[h],c=a(e,l);var d=i(c,r,n);-1!==d&&(c[d+2]|=P,m.push(d),f.push(c))}return g(o,u)}function p(e){var t=e.__ember_meta__.listeners,r=[];if(t)for(var n in t)t[n]&&r.push(n);return r}function m(e,t,r,n){if(e!==b&&"function"==typeof e.sendEvent&&e.sendEvent(t,r),!n){var i=e.__ember_meta__;n=i&&i.listeners&&i.listeners[t]}if(n){for(var a=n.length-3;a>=0;a-=3){var s=n[a],o=n[a+1],u=n[a+2];o&&(u&P||(u&E&&l(e,t,s,o),s||(s=e),"string"==typeof o?r?w(s,o,r):s[o]():r?_(s,o,r):o.call(s)))}return!0}}function f(e,t){var r=e.__ember_meta__,n=r&&r.listeners&&r.listeners[t];return!(!n||!n.length)}function d(e,t){var r=[],n=e.__ember_meta__,i=n&&n.listeners&&n.listeners[t];if(!i)return r;for(var a=0,s=i.length;s>a;a+=3){var o=i[a],u=i[a+1];r.push([o,u])}return r}function v(){var e=C.call(arguments,-1)[0],t=C.call(arguments,0,-1);return e.__ember_listens__=t,e}var b=e["default"],y=t.meta,g=t.tryFinally,_=t.apply,w=t.applyStr,x=r.create,C=[].slice,O=y,E=1,P=2;n.listenersUnion=s,n.listenersDiff=o,n.addListener=u,n.suspendListener=c,n.suspendListeners=h,n.watchedEvents=p,n.sendEvent=m,n.hasListeners=f,n.listenersFor=d,n.on=v,n.removeListener=l}),e("ember-metal/expand_properties",["ember-metal/core","ember-metal/error","ember-metal/enumerable_utils","exports"],function(e,t,r,n){"use strict";function i(e,t){if("string"===s.typeOf(e)){var r=e.split(l),n=[r];u(r,function(e,t){e.indexOf(",")>=0&&(n=a(n,e.split(","),t))}),u(n,function(e){t(e.join(""))})}else t(e)}function a(e,t,r){var n=[];return u(e,function(e){u(t,function(t){var i=e.slice(0);i[r]=t,n.push(i)})}),n}var s=e["default"],o=t["default"],u=r.forEach,l=/\{|\}/;n["default"]=function(e,t){if(e.indexOf(" ")>-1)throw new o("Brace expanded properties cannot contain spaces, e.g. `user.{firstName, lastName}` should be `user.{firstName,lastName}`");return i(e,t)}}),e("ember-metal/get_properties",["ember-metal/property_get","ember-metal/utils","exports"],function(e,t,r){"use strict";var n=e.get,i=t.typeOf;r["default"]=function(e){var t={},r=arguments,a=1;2===arguments.length&&"array"===i(arguments[1])&&(a=0,r=arguments[1]);for(var s=r.length;s>a;a++)t[r[a]]=n(e,r[a]);return t}}),e("ember-metal/instrumentation",["ember-metal/core","ember-metal/utils","exports"],function(e,t,r){"use strict";function n(e,t,r,n){if(0===c.length)return r.call(n);var a=t||{},s=i(e,function(){return a});if(s){var o=function(){return r.call(n)},u=function(e){a.exception=e};return l(o,u,s)}return r.call(n)}function i(e,t){var r=h[e];if(r||(r=p(e)),0!==r.length){var n,i=t(),a=u.STRUCTURED_PROFILE;a&&(n=e+": "+i.object,console.time(n));var s,o,l=r.length,c=new Array(l),f=m();for(s=0;l>s;s++)o=r[s],c[s]=o.before(e,f,i);return function(){var t,s,o,u=m();for(t=0,s=r.length;s>t;t++)o=r[t],o.after(e,u,i,c[t]);a&&console.timeEnd(n)}}}function a(e,t){for(var r,n=e.split("."),i=[],a=0,s=n.length;s>a;a++)r=n[a],i.push("*"===r?"[^\\.]*":r);i=i.join("\\."),i+="(\\..*)?";var o={pattern:e,regex:new RegExp("^"+i+"$"),object:t};return c.push(o),h={},o}function s(e){for(var t,r=0,n=c.length;n>r;r++)c[r]===e&&(t=r);c.splice(t,1),h={}}function o(){c.length=0,h={}}var u=e["default"],l=t.tryCatchFinally,c=[];r.subscribers=c;var h={},p=function(e){for(var t,r=[],n=0,i=c.length;i>n;n++)t=c[n],t.regex.test(e)&&r.push(t.object);return h[e]=r,r},m=function(){var e="undefined"!=typeof window?window.performance||{}:{},t=e.now||e.mozNow||e.webkitNow||e.msNow||e.oNow;return t?t.bind(e):function(){return+new Date}}();r.instrument=n,r._instrumentStart=i,r.subscribe=a,r.unsubscribe=s,r.reset=o}),e("ember-metal/is_blank",["ember-metal/core","ember-metal/is_empty","exports"],function(e,t,r){"use strict";var n=(e["default"],t["default"]);r["default"]=function(e){return n(e)||"string"==typeof e&&null===e.match(/\S/)}}),e("ember-metal/is_empty",["ember-metal/core","ember-metal/property_get","ember-metal/is_none","exports"],function(e,t,r,n){"use strict";function i(e){var t=o(e);if(t)return t;if("number"==typeof e.size)return!e.size;var r=typeof e;if("object"===r){var n=s(e,"size");if("number"==typeof n)return!n}if("number"==typeof e.length&&"function"!==r)return!e.length;if("object"===r){var i=s(e,"length");if("number"==typeof i)return!i}return!1}var a=e["default"],s=t.get,o=r["default"],u=a.deprecateFunc("Ember.empty is deprecated. Please use Ember.isEmpty instead.",i);n.empty=u,n["default"]=i,n.isEmpty=i,n.empty=u}),e("ember-metal/is_none",["ember-metal/core","exports"],function(e,t){"use strict";function r(e){return null===e||void 0===e}var n=e["default"],i=n.deprecateFunc("Ember.none is deprecated. Please use Ember.isNone instead.",r);t.none=i,t["default"]=r,t.isNone=r}),e("ember-metal/is_present",["ember-metal/is_blank","exports"],function(e,t){"use strict";var r,n=e["default"];r=function(e){return!n(e)},t["default"]=r}),e("ember-metal/keys",["ember-metal/platform","exports"],function(e,t){"use strict";var r=e.canDefineNonEnumerableProperties,n=Object.keys;n&&r||(n=function(){var e=Object.prototype.hasOwnProperty,t=!{toString:null}.propertyIsEnumerable("toString"),r=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],n=r.length;return function(i){if("object"!=typeof i&&("function"!=typeof i||null===i))throw new TypeError("Object.keys called on non-object");var a,s,o=[];for(a in i)"_super"!==a&&0!==a.lastIndexOf("__",0)&&e.call(i,a)&&o.push(a);if(t)for(s=0;n>s;s++)e.call(i,r[s])&&o.push(r[s]);return o}}()),t["default"]=n}),e("ember-metal/libraries",["ember-metal/enumerable_utils","exports"],function(e,t){"use strict";var r=e.forEach,n=e.indexOf,i=function(){var e=[],t=0,i=function(t){for(var r=0;r-1&&i.splice(a,1),this.size=i.length,!0}return!1},isEmpty:function(){return 0===this.size},has:function(e){if(0===this.size)return!1;var t=m(e),r=this.presenceSet;return r[t]===!0},forEach:function(e){if("function"!=typeof e&&s(e),0!==this.size){var t,r=this.list,n=arguments.length;if(2===n)for(t=0;ts;s++)n=i[s],e[n]=t[n];return e}}),e("ember-metal/mixin",["ember-metal/core","ember-metal/merge","ember-metal/array","ember-metal/platform","ember-metal/utils","ember-metal/expand_properties","ember-metal/properties","ember-metal/computed","ember-metal/binding","ember-metal/observer","ember-metal/events","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h){"use strict";function p(){var e,t=this.__nextSuper;if(t){for(var r=new Array(arguments.length),n=0,i=r.length;i>n;n++)r[n]=arguments[n];this.__nextSuper=null,e=Z(this,t,r),this.__nextSuper=t}return e}function m(e){var t=dt(e,!0),r=t.mixins;return r?t.hasOwnProperty("mixins")||(r=t.mixins=ft(r)):r=t.mixins={},r}function f(e,t){return t&&t.length>0&&(e.mixins=ct.call(t,function(e){if(e instanceof I)return e;var t=new I;return t.properties=e,t})),e}function d(e){return"function"==typeof e&&e.isMethod!==!1&&e!==Boolean&&e!==Object&&e!==Number&&e!==Array&&e!==Date&&e!==String}function v(e,t){var r;return t instanceof I?(r=Q(t),e[r]?vt:(e[r]=t,t.properties)):t}function b(e,t,r,n){var i;return i=r[e]||n[e],t[e]&&(i=i?i.concat(t[e]):t[e]),i}function y(e,t,r,n,i){var a;return void 0===n[t]&&(a=i[t]),a=a||e.descs[t],void 0!==a&&a instanceof rt?(r=ft(r),r.func=Y(r.func,a.func),r):r}function g(e,t,r,n,i){var a;return void 0===i[t]&&(a=n[t]),a=a||e[t],void 0===a||"function"!=typeof a?r:Y(r,a)}function _(e,t,r,n){var i=n[t]||e[t];return i?"function"==typeof i.concat?i.concat(r):J(i).concat(r):J(r)}function w(e,t,r,n){var i=n[t]||e[t];if(!i)return r;var a=B({},i),s=!1;for(var o in r)if(r.hasOwnProperty(o)){var u=r[o];d(u)?(s=!0,a[o]=g(e,o,u,i,{})):a[o]=u}return s&&(a._super=p),a}function x(e,t,r,n,i,a,s,o){if(r instanceof et){if(r===q&&i[t])return vt;r.func&&(r=y(n,t,r,a,i)),i[t]=r,a[t]=void 0}else s&&ht.call(s,t)>=0||"concatenatedProperties"===t||"mergedProperties"===t?r=_(e,t,r,a):o&&ht.call(o,t)>=0?r=w(e,t,r,a):d(r)&&(r=g(e,t,r,a,i)),i[t]=void 0,a[t]=r}function C(e,t,r,n,i,a){function s(e){delete r[e],delete n[e]}for(var o,u,l,c,h,p,m=0,f=e.length;f>m;m++)if(o=e[m],u=v(t,o),u!==vt)if(u){p=dt(i),i.willMergeMixin&&i.willMergeMixin(u),c=b("concatenatedProperties",u,n,i),h=b("mergedProperties",u,n,i);for(l in u)u.hasOwnProperty(l)&&(a.push(l),x(i,l,u[l],p,r,n,c,h));u.hasOwnProperty("toString")&&(i.toString=u.toString)}else o.mixins&&(C(o.mixins,t,r,n,i,a),o._without&&pt.call(o._without,s))}function O(e,t,r,n){if(bt.test(t)){var i=n.bindings;i?n.hasOwnProperty("bindings")||(i=n.bindings=ft(n.bindings)):i=n.bindings={},i[t]=r}}function E(e,t){var r,n,i,a=t.bindings;if(a){for(r in a)n=a[r],n&&(i=r.slice(0,-7),n instanceof nt?(n=n.copy(),n.to(i)):n=new nt(i,n),n.connect(e),e[r]=n);t.bindings={}}}function P(e,t){return E(e,t||dt(e)),e}function A(e,t,r,n,i){var a,s=t.methodName;return n[s]||i[s]?(a=i[s],t=n[s]):r.descs[s]?(t=r.descs[s],a=void 0):(t=void 0,a=e[s]),{desc:t,value:a}}function T(e,t,r,n,i){var a=r[n];if(a)for(var s=0,o=a.length;o>s;s++)i(e,a[s],null,t)}function N(e,t,r){var n=e[t];"function"==typeof n&&(T(e,t,n,"__ember_observesBefore__",ot),T(e,t,n,"__ember_observes__",at),T(e,t,n,"__ember_listens__",lt)),"function"==typeof r&&(T(e,t,r,"__ember_observesBefore__",st),T(e,t,r,"__ember_observes__",it),T(e,t,r,"__ember_listens__",ut))}function S(e,t,r){var n,i,a,s={},o={},u=dt(e),l=[];e._super=p,C(t,m(e),s,o,e,l);for(var c=0,h=l.length;h>c;c++)if(n=l[c],"constructor"!==n&&o.hasOwnProperty(n)&&(a=s[n],i=o[n],a!==q)){for(;a&&a instanceof M;){var f=A(e,a,u,s,o);a=f.desc,i=f.value}(void 0!==a||void 0!==i)&&(N(e,n,i),O(e,n,i,u),tt(e,n,a,i,u))}return r||P(e,u),e}function V(e){var t=mt.call(arguments,1);return S(e,t,!1),e}function I(){return f(this,arguments)}function k(e,t,r){var n=Q(e);if(r[n])return!1;if(r[n]=!0,e===t)return!0;for(var i=e.mixins,a=i?i.length:0;--a>=0;)if(k(i[a],t,r))return!0;return!1}function D(e,t,r){if(!r[Q(t)])if(r[Q(t)]=!0,t.properties){var n=t.properties;for(var i in n)n.hasOwnProperty(i)&&(e[i]=!0)}else t.mixins&&pt.call(t.mixins,function(t){D(e,t,r)})}function j(){return q}function M(e){this.methodName=e}function R(e){return new M(e)}function L(){var e,t=mt.call(arguments,-1)[0],r=function(t){e.push(t)},n=mt.call(arguments,0,-1);"function"!=typeof t&&(t=arguments[0],n=mt.call(arguments,1)),e=[];for(var i=0;ie;e++){arguments[e]}return L.apply(this,arguments)}function z(){var e,t=mt.call(arguments,-1)[0],r=function(t){e.push(t)},n=mt.call(arguments,0,-1);"function"!=typeof t&&(t=arguments[0],n=mt.call(arguments,1)),e=[];for(var i=0;ir;r++)e=arguments[r],e instanceof I?i.push(e):(t=I.create(),t.properties=e,i.push(t));return this},yt.apply=function(e){return S(e,[this],!1)},yt.applyPartial=function(e){return S(e,[this],!0)},yt.detect=function(e){if(!e)return!1;if(e instanceof I)return k(e,this,{});var t=e.__ember_meta__,r=t&&t.mixins;return r?!!r[Q(this)]:!1},yt.without=function(){var e=new I(this);return e._without=mt.call(arguments),e},yt.keys=function(){var e={},t={},r=[];D(e,this,t);for(var n in e)e.hasOwnProperty(n)&&r.push(n);return r},I.mixins=function(e){var t=e.__ember_meta__,r=t&&t.mixins,n=[];if(!r)return n;for(var i in r){var a=r[i];a.properties||n.push(a)}return n},q=new et,q.toString=function(){return"(Required Property)"},h.required=j,M.prototype=new et,h.aliasMethod=R,h.observer=L,h.immediateObserver=H,h.beforeObserver=z,h.IS_BINDING=bt,h.Mixin=I}),e("ember-metal/observer",["ember-metal/watching","ember-metal/array","ember-metal/events","exports"],function(e,t,r,n){"use strict";function i(e){return e+O}function a(e){return e+E}function s(e,t,r,n){return _(e,i(t),r,n),v(e,t),this}function o(e,t){return g(e,i(t))}function u(e,t,r,n){return b(e,t),w(e,i(t),r,n),this}function l(e,t,r,n){return _(e,a(t),r,n),v(e,t),this}function c(e,t,r,n,i){return C(e,a(t),r,n,i)}function h(e,t,r,n,a){return C(e,i(t),r,n,a)}function p(e,t,r,n,i){var s=y.call(t,a);return x(e,s,r,n,i)}function m(e,t,r,n,a){var s=y.call(t,i);return x(e,s,r,n,a)}function f(e,t){return g(e,a(t))}function d(e,t,r,n){return b(e,t),w(e,a(t),r,n),this}var v=e.watch,b=e.unwatch,y=t.map,g=r.listenersFor,_=r.addListener,w=r.removeListener,x=r.suspendListeners,C=r.suspendListener,O=":change",E=":before";n.addObserver=s,n.observersFor=o,n.removeObserver=u,n.addBeforeObserver=l,n._suspendBeforeObserver=c,n._suspendObserver=h,n._suspendBeforeObservers=p,n._suspendObservers=m,n.beforeObserversFor=f,n.removeBeforeObserver=d}),e("ember-metal/observer_set",["ember-metal/utils","ember-metal/events","exports"],function(e,t,r){"use strict";function n(){this.clear()}var i=e.guidFor,a=t.sendEvent;r["default"]=n,n.prototype.add=function(e,t,r){var n,a=this.observerSet,s=this.observers,o=i(e),u=a[o];return u||(a[o]=u={}),n=u[t],void 0===n&&(n=s.push({sender:e,keyName:t,eventName:r,listeners:[]})-1,u[t]=n),s[n].listeners},n.prototype.flush=function(){var e,t,r,n,i=this.observers;for(this.clear(),e=0,t=i.length;t>e;++e)r=i[e],n=r.sender,n.isDestroying||n.isDestroyed||a(n,r.eventName,[n,r.keyName],r.listeners)},n.prototype.clear=function(){this.observerSet={},this.observers=[]}}),e("ember-metal/path_cache",["ember-metal/cache","exports"],function(e,t){"use strict";function r(e){return c.get(e)}function n(e){return h.get(e)}function i(e){return p.get(e)}function a(e){return m.get(e)}var s=e["default"],o=/^([A-Z$]|([0-9][A-Z$]))/,u=/^([A-Z$]|([0-9][A-Z$])).*[\.]/,l="this.",c=new s(1e3,function(e){return o.test(e)}),h=new s(1e3,function(e){return u.test(e)}),p=new s(1e3,function(e){return-1!==e.indexOf(l)}),m=new s(1e3,function(e){return-1!==e.indexOf(".")}),f={isGlobalCache:c,isGlobalPathCache:h,hasThisCache:p,isPathCache:m};t.caches=f,t.isGlobal=r,t.isGlobalPath=n,t.hasThis=i,t.isPath=a}),e("ember-metal/platform",["ember-metal/platform/define_property","ember-metal/platform/define_properties","ember-metal/platform/create","exports"],function(e,t,r,n){"use strict";var i=e.hasES5CompliantDefineProperty,a=e.defineProperty,s=t["default"],o=r["default"],u=i,l=i;n.create=o,n.defineProperty=a,n.defineProperties=s,n.hasPropertyAccessors=u,n.canDefineNonEnumerableProperties=l}),e("ember-metal/platform/create",["exports"],function(e){var t;if(!Object.create||Object.create(null).hasOwnProperty){var r,n=!({__proto__:null}instanceof Object);r=n||"undefined"==typeof document?function(){return{__proto__:null}}:function(){function e(){}var t=document.createElement("iframe"),n=document.body||document.documentElement;t.style.display="none",n.appendChild(t),t.src="javascript:";var i=t.contentWindow.Object.prototype;return n.removeChild(t),t=null,delete i.constructor,delete i.hasOwnProperty,delete i.propertyIsEnumerable,delete i.isPrototypeOf,delete i.toLocaleString,delete i.toString,delete i.valueOf,e.prototype=i,r=function(){return new e},new e},t=Object.create=function(e,t){function n(){}var i;if(null===e)i=r();else{if("object"!=typeof e&&"function"!=typeof e)throw new TypeError("Object prototype may only be an Object or null");n.prototype=e,i=new n}return void 0!==t&&Object.defineProperties(i,t),i}}else t=Object.create;e["default"]=t}),e("ember-metal/platform/define_properties",["ember-metal/platform/define_property","exports"],function(e,t){"use strict";var r=e.defineProperty,n=Object.defineProperties;n||(n=function(e,t){for(var n in t)t.hasOwnProperty(n)&&"__proto__"!==n&&r(e,n,t[n]);return e},Object.defineProperties=n),t["default"]=n}),e("ember-metal/platform/define_property",["exports"],function(e){"use strict";var t=function(e){if(e)try{var t=5,r={};if(e(r,"a",{configurable:!0,enumerable:!0,get:function(){return t},set:function(e){t=e}}),5!==r.a)return;if(r.a=10,10!==t)return;e(r,"a",{configurable:!0,enumerable:!1,writable:!0,value:!0});for(var n in r)if("a"===n)return;if(r.a!==!0)return;return e}catch(i){return}}(Object.defineProperty),r=!!t;if(r&&"undefined"!=typeof document){var n=function(){try{return t(document.createElement("div"),"definePropertyOnDOM",{}),!0}catch(e){}return!1}();n||(t=function(e,t,r){var n;return n="object"==typeof Node?e instanceof Node:"object"==typeof e&&"number"==typeof e.nodeType&&"string"==typeof e.nodeName,n?e[t]=r.value:Object.defineProperty(e,t,r)})}r||(t=function(e,t,r){r.get||(e[t]=r.value)}),e.hasES5CompliantDefineProperty=r,e.defineProperty=t}),e("ember-metal/properties",["ember-metal/core","ember-metal/utils","ember-metal/platform","ember-metal/property_events","exports"],function(e,t,r,n,i){"use strict";function a(){}function s(){return function(){}}function o(e){return function(){var t=this.__ember_meta__;return t&&t.values[e]}}function u(e,t,r,n,i){var s,o,u,p;i||(i=l(e)),s=i.descs,o=i.descs[t];var m=i.watching[t];return u=void 0!==m&&m>0,o instanceof a&&o.teardown(e,t),r instanceof a?(p=r,s[t]=r,e[t]=void 0,r.setup&&r.setup(e,t)):(s[t]=void 0,null==r?(p=n,e[t]=n):(p=r,c(e,t,r))),u&&h(e,t,i),e.didDefineProperty&&e.didDefineProperty(e,t,p),this}var l=(e["default"],t.meta),c=r.defineProperty,h=(r.hasPropertyAccessors,n.overrideChains);i.Descriptor=a,i.MANDATORY_SETTER_FUNCTION=s,i.DEFAULT_GETTER_FUNCTION=o,i.defineProperty=u}),e("ember-metal/property_events",["ember-metal/utils","ember-metal/events","ember-metal/observer_set","exports"],function(e,t,r,n){"use strict";function i(e,t){var r=e.__ember_meta__,n=r&&r.watching[t]>0||"length"===t,i=r&&r.proto,a=r&&r.descs[t];n&&i!==e&&(a&&a.willChange&&a.willChange(e,t),s(e,t,r),c(e,t,r),v(e,t))}function a(e,t){var r=e.__ember_meta__,n=r&&r.watching[t]>0||"length"===t,i=r&&r.proto,a=r&&r.descs[t]; +i!==e&&(a&&a.didChange&&a.didChange(e,t),(n||"length"===t)&&(r&&r.deps&&r.deps[t]&&o(e,t,r),h(e,t,r,!1),b(e,t)))}function s(e,t,r){if(!e.isDestroying){var n;if(r&&r.deps&&(n=r.deps[t])){var a=y,s=!a;s&&(a=y={}),l(i,e,n,t,a,r),s&&(y=null)}}}function o(e,t,r){if(!e.isDestroying){var n;if(r&&r.deps&&(n=r.deps[t])){var i=g,s=!i;s&&(i=g={}),l(a,e,n,t,i,r),s&&(g=null)}}}function u(e){var t=[];for(var r in e)t.push(r);return t}function l(e,t,r,n,i,a){var s,o,l,c,h=_(t),p=i[h];if(p||(p=i[h]={}),!p[n]&&(p[n]=!0,r)){s=u(r);var m=a.descs;for(l=0;ln;n++)s[n].willChange(o);for(n=0,a=o.length;a>n;n+=2)i(o[n],o[n+1])}}function h(e,t,r,n){if(r&&r.hasOwnProperty("chainWatchers")&&r.chainWatchers[t]){var i,s,o=r.chainWatchers[t],u=n?null:[];for(i=0,s=o.length;s>i;i++)o[i].didChange(u);if(!n)for(i=0,s=u.length;s>i;i+=2)a(u[i],u[i+1])}}function p(e,t,r){h(e,t,r,!0)}function m(){T++}function f(){T--,0>=T&&(P.clear(),A.flush())}function d(e,t){m(),w(e,f,t)}function v(e,t){if(!e.isDestroying){var r,n,i=t+":before";T?(r=P.add(e,t,i),n=O(e,i,r),x(e,i,[e,t],n)):x(e,i,[e,t])}}function b(e,t){if(!e.isDestroying){var r,n=t+":change";T?(r=A.add(e,t,n),C(e,n,r)):x(e,n,[e,t])}}var y,g,_=e.guidFor,w=e.tryFinally,x=t.sendEvent,C=t.listenersUnion,O=t.listenersDiff,E=r["default"],P=new E,A=new E,T=0;n.propertyWillChange=i,n.propertyDidChange=a,n.overrideChains=p,n.beginPropertyChanges=m,n.endPropertyChanges=f,n.changeProperties=d}),e("ember-metal/property_get",["ember-metal/core","ember-metal/error","ember-metal/path_cache","ember-metal/platform","exports"],function(e,t,r,n,i){"use strict";function a(e,t){var r,n=p(t),i=!n&&c(t);if((!e||i)&&(e=u.lookup),n&&(t=t.slice(5)),e===u.lookup&&(r=t.match(m)[0],e=f(e,r),t=t.slice(r.length+1)),!t||0===t.length)throw new l("Path cannot be empty");return[e,t]}function s(e,t){var r,n,i,s,o;if(null===e&&!h(t))return f(u.lookup,t);for(r=p(t),(!e||r)&&(i=a(e,t),e=i[0],t=i[1],i.length=0),n=t.split("."),o=n.length,s=0;null!=e&&o>s;s++)if(e=f(e,n[s],!0),e&&e.isDestroyed)return void 0;return e}function o(e,t,r){var n=f(e,t);return void 0===n?r:n}var u=e["default"],l=t["default"],c=r.isGlobalPath,h=r.isPath,p=r.hasThis,m=(n.hasPropertyAccessors,/^([^\.]+)/),f=function(e,t){if(""===t)return e;if(t||"string"!=typeof e||(t=e,e=null),null===e){var r=s(e,t);return r}var n,i=e.__ember_meta__,a=i&&i.descs[t];return void 0===a&&h(t)?s(e,t):a?a.get(e,t):(n=e[t],void 0!==n||"object"!=typeof e||t in e||"function"!=typeof e.unknownProperty?n:e.unknownProperty(t))};u.config.overrideAccessors&&(u.get=f,u.config.overrideAccessors(),f=u.get),i.getWithDefault=o,i["default"]=f,i.get=f,i.normalizeTuple=a,i._getPath=s}),e("ember-metal/property_set",["ember-metal/core","ember-metal/property_get","ember-metal/property_events","ember-metal/properties","ember-metal/error","ember-metal/path_cache","ember-metal/platform","exports"],function(e,t,r,n,i,a,s,o){"use strict";function u(e,t,r,n){var i;if(i=t.slice(t.lastIndexOf(".")+1),t=t===i?i:t.slice(0,t.length-(i.length+1)),"this"!==t&&(e=h(e,t)),!i||0===i.length)throw new f("Property set failed: You passed an empty path");if(!e){if(n)return;throw new f('Property set failed: object in path "'+t+'" could not be found or was destroyed.')}return v(e,i,r)}function l(e,t,r){return v(e,t,r,!0)}var c=e["default"],h=t._getPath,p=r.propertyWillChange,m=r.propertyDidChange,f=(n.defineProperty,i["default"]),d=a.isPath,v=(s.hasPropertyAccessors,function(e,t,r,n){if("string"==typeof e&&(r=t,t=e,e=null),!e)return u(e,t,r,n);var i,a,s=e.__ember_meta__,o=s&&s.descs[t];if(void 0===o&&d(t))return u(e,t,r,n);if(void 0!==o)o.set(e,t,r);else{if("object"==typeof e&&null!==e&&void 0!==r&&e[t]===r)return r;i="object"==typeof e&&!(t in e),i&&"function"==typeof e.setUnknownProperty?e.setUnknownProperty(t,r):s&&s.watching[t]>0?(a=e[t],r!==a&&(p(e,t),e[t]=r,m(e,t))):e[t]=r}return r});c.config.overrideAccessors&&(c.set=v,c.config.overrideAccessors(),v=c.set),o.trySet=l,o.set=v}),e("ember-metal/run_loop",["ember-metal/core","ember-metal/utils","ember-metal/array","ember-metal/property_events","backburner","exports"],function(e,t,r,n,i,a){"use strict";function s(e){u.currentRunLoop=e}function o(e,t){u.currentRunLoop=t}function u(){return b.run.apply(b,arguments)}function l(){!u.currentRunLoop}{var c=e["default"],h=t.apply,p=t.GUID_KEY,m=r.indexOf,f=n.beginPropertyChanges,d=n.endPropertyChanges,v=i["default"],b=new v(["sync","actions","destroy"],{GUID_KEY:p,sync:{before:f,after:d},defaultQueue:"actions",onBegin:s,onEnd:o,onErrorTarget:c,onErrorMethod:"onerror"}),y=[].slice;[].concat}a["default"]=u,u.join=function(){if(!u.currentRunLoop)return c.run.apply(c,arguments);var e=y.call(arguments);e.unshift("actions"),u.schedule.apply(u,e)},u.bind=function(){var e=y.call(arguments);return function(){return u.join.apply(u,e.concat(y.call(arguments)))}},u.backburner=b,u.currentRunLoop=null,u.queues=b.queueNames,u.begin=function(){b.begin()},u.end=function(){b.end()},u.schedule=function(){l(),b.schedule.apply(b,arguments)},u.hasScheduledTimers=function(){return b.hasTimers()},u.cancelTimers=function(){b.cancelTimers()},u.sync=function(){b.currentInstance&&b.currentInstance.queues.sync.flush()},u.later=function(){return b.later.apply(b,arguments)},u.once=function(){l();var e=y.call(arguments);return e.unshift("actions"),h(b,b.scheduleOnce,e)},u.scheduleOnce=function(){return l(),b.scheduleOnce.apply(b,arguments)},u.next=function(){var e=y.call(arguments);return e.push(1),h(b,b.later,e)},u.cancel=function(e){return b.cancel(e)},u.debounce=function(){return b.debounce.apply(b,arguments)},u.throttle=function(){return b.throttle.apply(b,arguments)},u._addQueue=function(e,t){-1===m.call(u.queues,e)&&u.queues.splice(m.call(u.queues,t)+1,0,e)}}),e("ember-metal/set_properties",["ember-metal/property_events","ember-metal/property_set","ember-metal/keys","exports"],function(e,t,r,n){"use strict";var i=e.changeProperties,a=t.set,s=r["default"];n["default"]=function(e,t){return t&&"object"==typeof t?(i(function(){for(var r,n=s(t),i=0,o=n.length;o>i;i++)r=n[i],a(e,r,t[r])}),e):e}}),e("ember-metal/utils",["ember-metal/core","ember-metal/platform","ember-metal/array","exports"],function(e,t,r,n){"use strict";function i(){return++A}function a(e){var t={};t[e]=1;for(var r in t)if(r===e)return r;return e}function s(e,t){t||(t=T);var r=t+i();return e&&(null===e[I]?e[I]=r:(k.value=r,C(e,I,k))),r}function o(e){if(void 0===e)return"(undefined)";if(null===e)return"(null)";var t,r=typeof e;switch(r){case"number":return t=S[e],t||(t=S[e]="nu"+e),t;case"string":return t=V[e],t||(t=V[e]="st"+i()),t;case"boolean":return e?"(true)":"(false)";default:return e[I]?e[I]:e===Object?"(Object)":e===Array?"(Array)":(t=T+i(),null===e[I]?e[I]=t:(k.value=t,C(e,I,k)),t)}}function u(e){this.descs={},this.watching={},this.cache={},this.cacheMeta={},this.source=e}function l(e,t){var r=e.__ember_meta__;return t===!1?r||j:(r?r.source!==e&&(O&&C(e,"__ember_meta__",D),r=N(r),r.descs=N(r.descs),r.watching=N(r.watching),r.cache={},r.cacheMeta={},r.source=e,e.__ember_meta__=r):(O&&C(e,"__ember_meta__",D),r=new u(e),e.__ember_meta__=r,r.descs.constructor=null),r)}function c(e,t){var r=l(e,!1);return r[t]}function h(e,t,r){var n=l(e,!0);return n[t]=r,r}function p(e,t,r){for(var n,i,a=l(e,r),s=0,o=t.length;o>s;s++){if(n=t[s],i=a[n]){if(i.__ember_source__!==e){if(!r)return void 0;i=a[n]=N(i),i.__ember_source__=e}}else{if(!r)return void 0;i=a[n]={__ember_source__:e}}a=i}return i}function m(e,t){function r(){for(var r,n=this&&this.__nextSuper,i=new Array(arguments.length),a=0,s=i.length;s>a;a++)i[a]=arguments[a];return this&&(this.__nextSuper=t),r=_(this,e,i),this&&(this.__nextSuper=n),r}return r.wrappedFunction=e,r.wrappedFunction.__ember_arity__=e.length,r.__ember_observes__=e.__ember_observes__,r.__ember_observesBefore__=e.__ember_observesBefore__,r.__ember_listens__=e.__ember_listens__,r}function f(e){var t,r;return"undefined"==typeof M&&(t="ember-runtime/mixins/array",x.__loader.registry[t]&&(M=x.__loader.require(t)["default"])),!e||e.setInterval?!1:Array.isArray&&Array.isArray(e)?!0:M&&M.detect(e)?!0:(r=y(e),"array"===r?!0:void 0!==e.length&&"object"===r?!0:!1)}function d(e){return null===e||void 0===e?[]:f(e)?e:[e]}function v(e,t){return!(!e||"function"!=typeof e[t])}function b(e,t,r){return v(e,t)?r?w(e,t,r):w(e,t):void 0}function y(e){var t,r;return"undefined"==typeof F&&(r="ember-runtime/system/object",x.__loader.registry[r]&&(F=x.__loader.require(r)["default"])),t=null===e||void 0===e?String(e):z[B.call(e)]||"object","function"===t?F&&F.detect(e)&&(t="class"):"object"===t&&(e instanceof Error?t="error":F&&e instanceof F?t="instance":e instanceof Date&&(t="date")),t}function g(e){var t=y(e);if("array"===t)return"["+e+"]";if("object"!==t)return e+"";var r,n=[];for(var i in e)if(e.hasOwnProperty(i)){if(r=e[i],"toString"===r)continue;"function"===y(r)&&(r="function() { ... }"),n.push(r&&"function"!=typeof r.toString?i+": "+B.call(r):i+": "+r)}return"{"+n.join(", ")+"}"}function _(e,t,r){var n=r&&r.length;if(!r||!n)return t.call(e);switch(n){case 1:return t.call(e,r[0]);case 2:return t.call(e,r[0],r[1]);case 3:return t.call(e,r[0],r[1],r[2]);case 4:return t.call(e,r[0],r[1],r[2],r[3]);case 5:return t.call(e,r[0],r[1],r[2],r[3],r[4]);default:return t.apply(e,r)}}function w(e,t,r){var n=r&&r.length;if(!r||!n)return e[t]();switch(n){case 1:return e[t](r[0]);case 2:return e[t](r[0],r[1]);case 3:return e[t](r[0],r[1],r[2]);case 4:return e[t](r[0],r[1],r[2],r[3]);case 5:return e[t](r[0],r[1],r[2],r[3],r[4]);default:return e[t].apply(e,r)}}var x=e["default"],C=t.defineProperty,O=t.canDefineNonEnumerableProperties,E=(t.hasPropertyAccessors,t.create),P=r.forEach,A=0;n.uuid=i;var T="ember",N=E,S=[],V={},I=a("__ember"+ +new Date),k={writable:!1,configurable:!1,enumerable:!1,value:null};n.generateGuid=s,n.guidFor=o;var D={writable:!0,configurable:!1,enumerable:!1,value:null};u.prototype={descs:null,deps:null,watching:null,listeners:null,cache:null,cacheMeta:null,source:null,mixins:null,bindings:null,chains:null,chainWatchers:null,values:null,proto:null},O||(u.prototype.__preventPlainObject__=!0,u.prototype.toJSON=function(){});var j=new u(null);n.getMeta=c,n.setMeta=h,n.metaPath=p,n.wrap=m;var M;n.makeArray=d,n.tryInvoke=b;var R,L=function(){var e=0;try{try{}finally{throw e++,new Error("needsFinallyFixTest")}}catch(t){}return 1!==e}();R=L?function(e,t,r){var n,i,a;r=r||this;try{n=e.call(r)}finally{try{i=t.call(r)}catch(s){a=s}}if(a)throw a;return void 0===i?n:i}:function(e,t,r){var n,i;r=r||this;try{n=e.call(r)}finally{i=t.call(r)}return void 0===i?n:i};var H;H=L?function(e,t,r,n){var i,a,s;n=n||this;try{i=e.call(n)}catch(o){i=t.call(n,o)}finally{try{a=r.call(n)}catch(u){s=u}}if(s)throw s;return void 0===a?i:a}:function(e,t,r,n){var i,a;n=n||this;try{i=e.call(n)}catch(s){i=t.call(n,s)}finally{a=r.call(n)}return void 0===a?i:a};var z={},q="Boolean Number String Function Array Date RegExp Object".split(" ");P.call(q,function(e){z["[object "+e+"]"]=e.toLowerCase()});var F,B=Object.prototype.toString;n.inspect=g,n.apply=_,n.applyStr=w,n.GUID_KEY=I,n.META_DESC=D,n.EMPTY_META=j,n.meta=l,n.typeOf=y,n.tryCatchFinally=H,n.isArray=f,n.canInvoke=v,n.tryFinally=R}),e("ember-metal/watch_key",["ember-metal/core","ember-metal/utils","ember-metal/platform","ember-metal/properties","exports"],function(e,t,r,n,i){"use strict";function a(e,t,r){if("length"!==t||"array"!==u(e)){var n=r||l(e),i=n.watching;if(i[t])i[t]=(i[t]||0)+1;else{i[t]=1;var a=n.descs[t];a&&a.willWatch&&a.willWatch(e,t),"function"==typeof e.willWatchProperty&&e.willWatchProperty(t)}}}function s(e,t,r){var n=r||l(e),i=n.watching;if(1===i[t]){i[t]=0;var a=n.descs[t];a&&a.didUnwatch&&a.didUnwatch(e,t),"function"==typeof e.didUnwatchProperty&&e.didUnwatchProperty(t)}else i[t]>1&&i[t]--}var o=(e["default"],t.meta),u=t.typeOf,l=(r.defineProperty,r.hasPropertyAccessors,n.MANDATORY_SETTER_FUNCTION,n.DEFAULT_GETTER_FUNCTION,o);i.watchKey=a,i.unwatchKey=s}),e("ember-metal/watch_path",["ember-metal/utils","ember-metal/chains","exports"],function(e,t,r){"use strict";function n(e,t){var r=t||l(e),n=r.chains;return n?n.value()!==e&&(n=r.chains=n.copy(e)):n=r.chains=new u(null,null,e),n}function i(e,t,r){if("length"!==t||"array"!==o(e)){var i=r||l(e),a=i.watching;a[t]?a[t]=(a[t]||0)+1:(a[t]=1,n(e,i).add(t))}}function a(e,t,r){var i=r||l(e),a=i.watching;1===a[t]?(a[t]=0,n(e,i).remove(t)):a[t]>1&&a[t]--}var s=e.meta,o=e.typeOf,u=t.ChainNode,l=s;r.watchPath=i,r.unwatchPath=a}),e("ember-metal/watching",["ember-metal/utils","ember-metal/chains","ember-metal/watch_key","ember-metal/watch_path","ember-metal/path_cache","exports"],function(e,t,r,n,i,a){"use strict";function s(e,t,r){("length"!==t||"array"!==p(e))&&(_(t)?y(e,t,r):v(e,t,r))}function o(e,t){var r=e.__ember_meta__;return(r&&r.watching[t])>0}function u(e,t,r){("length"!==t||"array"!==p(e))&&(_(t)?g(e,t,r):b(e,t,r))}function l(e){var t=e.__ember_meta__,r=t&&t.chains;h in e&&!e.hasOwnProperty(h)&&m(e),r&&r.value()!==e&&(t.chains=r.copy(e))}function c(e){var t,r,n,i,a=e.__ember_meta__;if(a&&(e.__ember_meta__=null,t=a.chains))for(w.push(t);w.length>0;){if(t=w.pop(),r=t._chains)for(n in r)r.hasOwnProperty(n)&&w.push(r[n]);t._watching&&(i=t._object,i&&f(i,t._key,t))}}var h=(e.meta,e.GUID_KEY),p=e.typeOf,m=e.generateGuid,f=t.removeChainWatcher,d=t.flushPendingChains,v=r.watchKey,b=r.unwatchKey,y=n.watchPath,g=n.unwatchPath,_=i.isPath;a.watch=s,a.isWatching=o,s.flushPending=d,a.unwatch=u,a.rewatch=l;var w=[];a.destroy=c}),e("ember-routing-handlebars",["ember-metal/core","ember-handlebars","ember-routing/system/router","ember-routing-handlebars/helpers/shared","ember-routing-handlebars/helpers/link_to","ember-routing-handlebars/helpers/outlet","ember-routing-handlebars/helpers/render","ember-routing-handlebars/helpers/action","exports"],function(e,t,r,n,i,a,s,o,u){"use strict";var l=e["default"],c=t["default"],h=r["default"],p=n.resolvePaths,m=n.resolveParams,f=i.deprecatedLinkToHelper,d=i.linkToHelper,v=i.LinkView,b=i.queryParamsHelper,y=a.outletHelper,g=a.OutletView,_=s["default"],w=o.ActionHelper,x=o.actionHelper;h.resolveParams=m,h.resolvePaths=p,l.LinkView=v,c.ActionHelper=w,c.OutletView=g,c.registerHelper("render",_),c.registerHelper("action",x),c.registerHelper("outlet",y),c.registerHelper("link-to",d),c.registerHelper("linkTo",f),c.registerHelper("query-params",b),u["default"]=l}),e("ember-routing-handlebars/helpers/action",["ember-metal/core","ember-metal/property_get","ember-metal/array","ember-metal/utils","ember-metal/run_loop","ember-views/system/utils","ember-views/system/action_manager","ember-routing/system/router","ember-handlebars","ember-handlebars/ext","ember-handlebars/helpers/view","ember-routing-handlebars/helpers/shared","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p){"use strict";function m(e,t){var r=[];t&&r.push(t);var n=e.options.types.slice(1),i=e.options.data;return r.concat(x(e.context,e.params,{types:n,data:i}))}function f(e){var t=arguments[arguments.length-1],r=O.call(arguments,1,-1),n=t.hash,i=t.data.keywords.controller,a={eventName:n.on||"click",parameters:{context:this,options:t,params:r},view:t.data.view,bubbles:n.bubbles,preventDefault:n.preventDefault,target:{options:t},withKeyCode:n.withKeyCode,boundProperty:"ID"===t.types[0]};n.target?(a.target.root=this,a.target.target=n.target):i&&(a.target.root=i);var s=E.registerAction(e,a,n.allowedKeys);return new C('data-ember-action="'+s+'"')}var d=(e["default"],t.get,r.forEach),v=n.uuid,b=i["default"],y=a.isSimpleClick,g=s["default"],_=(o["default"],u["default"]),w=l.handlebarsGet,x=(c.viewHelper,h.resolveParams),C=(h.resolvePath,_.SafeString),O=Array.prototype.slice,E={};E.registeredActions=g.registeredActions,p.ActionHelper=E;var P=["alt","shift","meta","ctrl"],A=/^click|mouse|touch/,T=function(e,t){if("undefined"==typeof t){if(A.test(e.type))return y(e);t=""}if(t.indexOf("any")>=0)return!0;var r=!0;return d.call(P,function(n){e[n+"Key"]&&-1===t.indexOf(n)&&(r=!1)}),r};E.registerAction=function(e,t,r){var n=v();return g.registeredActions[n]={eventName:t.eventName,handler:function(n){if(!T(n,r))return!0;t.preventDefault!==!1&&n.preventDefault(),t.bubbles===!1&&n.stopPropagation();{var i,a=t.target,s=t.parameters;t.eventName}a=a.target?w(a.root,a.target,a.options):a.root,t.boundProperty&&(i=x(s.context,[e],{types:["ID"],data:s.options.data})[0],("undefined"==typeof i||"function"==typeof i)&&(i=e)),i||(i=e),b(function(){a.send?a.send.apply(a,m(s,i)):a[i].apply(a,m(s))})}},t.view.on("willClearRender",function(){delete g.registeredActions[n]}),n},p.actionHelper=f}),e("ember-routing-handlebars/helpers/link_to",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/merge","ember-metal/run_loop","ember-metal/computed","ember-runtime/system/lazy_load","ember-runtime/system/string","ember-runtime/system/object","ember-metal/keys","ember-views/system/utils","ember-views/views/component","ember-handlebars","ember-handlebars/helpers/view","ember-routing/system/router","ember-routing-handlebars/helpers/shared","exports"],function(e,r,n,i,a,s,o,u,l,c,h,p,m,f,d,v,b){"use strict";function y(e){var t=e.options.types,r=e.options.data;return R(e.context,e.params,{types:t,data:r})}function g(){var e=H.call(arguments,-1)[0],t=H.call(arguments,0,-1),r=e.hash;if(t[t.length-1]instanceof q&&(r.queryParamsObject=t.pop()),r.disabledBinding=r.disabledWhen,!e.fn){var n=t.shift(),i=e.types.shift(),a=this;"ID"===i?(e.linkTextPath=n,e.fn=function(){return D.getEscaped(a,n,e)}):e.fn=function(){return n}}return r.parameters={context:this,options:e,params:t},e.helperName=e.helperName||"link-to",j.call(this,F,e)}function _(e){return q.create({values:e.hash,types:e.hashTypes})}function w(){return g.apply(this,arguments)}function x(e){var t=e.parameters,r=e.queryParamsObject,n={};if(!r)return n;var i=r.values;for(var a in i)if(i.hasOwnProperty(a)){var s=i[a],o=r.types[a];if("ID"===o){var u=C(s,t);s=D.get(u.root,u.path,t.options)}n[a]=s}return n}function C(e,t){return D.normalizePath(t.context,e,t.options.data)}function O(e){for(var t=0,r=e.length;r>t;++t){var n=e[t];if(null===n||"undefined"==typeof n)return!1}return!0}function E(e,t){var r;for(r in e)if(e.hasOwnProperty(r)&&e[r]!==t[r])return!1;for(r in t)if(t.hasOwnProperty(r)&&e[r]!==t[r])return!1;return!0}var P=e["default"],A=r.get,T=(n.set,i["default"]),N=a["default"],S=s.computed,V=(o.onLoad,u.fmt,l["default"]),I=(c["default"],h.isSimpleClick),k=p["default"],D=m["default"],j=f.viewHelper,M=(d["default"],v.resolveParams),R=v.resolvePaths,L=v.routeArgs,H=[].slice;t("ember-handlebars");var z=function(e,t){for(var r=0,n=0,i=t.length;i>n&&(r+=t[n].names.length,t[n].handler!==e);n++);return r},q=V.extend({values:null}),F=P.LinkView=k.extend({tagName:"a",currentWhen:null,"current-when":null,title:null,rel:null,activeClass:"active",loadingClass:"loading",disabledClass:"disabled",_isDisabled:!1,replace:!1,attributeBindings:["href","title","rel","tabindex"],classNameBindings:["active","loading","disabled"],eventName:"click",init:function(){this._super.apply(this,arguments);var e=A(this,"eventName");this.on(e,this,this._invoke)},_paramsChanged:function(){this.notifyPropertyChange("resolvedParams")},_setupPathObservers:function(){var e,t,r,n=this.parameters,i=n.options.linkTextPath,a=y(n),s=a.length;for(i&&(r=C(i,n),this.registerObserver(r.root,r.path,this,this.rerender)),t=0;s>t;t++)e=a[t],null!==e&&(r=C(e,n),this.registerObserver(r.root,r.path,this,this._paramsChanged));var o=this.queryParamsObject;if(o){var u=o.values;for(var l in u)u.hasOwnProperty(l)&&"ID"===o.types[l]&&(r=C(u[l],n),this.registerObserver(r.root,r.path,this,this._paramsChanged))}},afterRender:function(){this._super.apply(this,arguments),this._setupPathObservers()},disabled:S(function(e,t){return void 0!==t&&this.set("_isDisabled",t),t?A(this,"disabledClass"):!1}),active:S("loadedParams",function(){function e(e){var i=t.router.recognizer.handlersFor(e),s=i[i.length-1].handler,o=z(e,i);n.length>o&&(e=s);var u=L(e,n,null),l=t.isActive.apply(t,u);if(!l)return!1;var c=P.isEmpty(P.keys(r.queryParams));if(!a&&!c&&l){var h={};T(h,r.queryParams),t._prepareQueryParams(r.targetRouteName,r.models,h),l=E(h,t.router.state.queryParams)}return l}if(A(this,"loading"))return!1;var t=A(this,"router"),r=A(this,"loadedParams"),n=r.models,i=this["current-when"]||this.currentWhen,a=Boolean(i);i=i||r.targetRouteName,i=i.split(" ");for(var s=0,o=i.length;o>s;s++)if(e(i[s]))return A(this,"activeClass")}),loading:S("loadedParams",function(){return A(this,"loadedParams")?void 0:A(this,"loadingClass")}),router:S(function(){var e=A(this,"controller");return e&&e.container?e.container.lookup("router:main"):void 0}),_invoke:function(e){if(!I(e))return!0;if(this.preventDefault!==!1){var t=A(this,"target");t&&"_self"!==t||e.preventDefault()}if(this.bubbles===!1&&e.stopPropagation(),A(this,"_isDisabled"))return!1;if(A(this,"loading"))return P.Logger.warn("This link-to is in an inactive loading state because at least one of its parameters presently has a null/undefined value, or the provided route name is invalid."),!1;var r=A(this,"target");if(r&&"_self"!==r)return!1;var n=A(this,"router"),i=A(this,"loadedParams"),a=n._doTransition(i.targetRouteName,i.models,i.queryParams);A(this,"replace")&&a.method("replace");var s=L(i.targetRouteName,i.models,a.state.queryParams),o=n.router.generate.apply(n.router,s);N.scheduleOnce("routerTransitions",this,this._eagerUpdateUrl,a,o)},_eagerUpdateUrl:function(e,t){if(e.isActive&&e.urlMethod){0===t.indexOf("#")&&(t=t.slice(1));var r=A(this,"router.router");"update"===e.urlMethod?r.updateURL(t):"replace"===e.urlMethod&&r.replaceURL(t),e.method(null)}},resolvedParams:S("router.url",function(){var e,t,r=this.parameters,n=r.options,i=n.types,a=n.data,s=0===r.params.length;if(s){var o=this.container.lookup("controller:application");e=A(o,"currentRouteName"),t=[]}else t=M(r.context,r.params,{types:i,data:a}),e=t.shift();var u=x(this,e);return{targetRouteName:e,models:t,queryParams:u}}),loadedParams:S("resolvedParams",function(){var e=A(this,"router");if(e){var t=A(this,"resolvedParams"),r=t.targetRouteName;if(r&&O(t.models))return t}}),queryParamsObject:null,href:S("loadedParams",function(){if("a"===A(this,"tagName")){var e=A(this,"router"),t=A(this,"loadedParams");if(!t)return A(this,"loadingHref");var r={};T(r,t.queryParams),e._prepareQueryParams(t.targetRouteName,t.models,r);var n=L(t.targetRouteName,t.models,r),i=e.generate.apply(e,n);return i}}),loadingHref:"#"});F.toString=function(){return"LinkView"},F.reopen({attributeBindings:["target"],target:null}),b.queryParamsHelper=_,b.LinkView=F,b.deprecatedLinkToHelper=w,b.linkToHelper=g}),e("ember-routing-handlebars/helpers/outlet",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/lazy_load","ember-views/views/container_view","ember-handlebars/views/metamorph_view","ember-handlebars/helpers/view","exports"],function(e,t,r,n,i,a,s,o){"use strict";function u(e,t){var r,n,i,a,s;for(e&&e.data&&e.data.isRenderData&&(t=e,e="main"),n=t.data.view.container,r=t.data.view;!r.get("template.isTop");)r=r.get("_parentView");return i=t.hash.view,i&&(s="view:"+i),a=i?n.lookupFactory(s):t.hash.viewClass||p,t.data.view.set("outletSource",r),t.hash.currentViewBinding="_view.outletSource._outlets."+e,t.helperName=t.helperName||"outlet",h.call(this,a,t)}var l=(e["default"],t.get,r.set,n.onLoad,i["default"]),c=a._Metamorph,h=s.viewHelper,p=l.extend(c);o.OutletView=p,o.outletHelper=u}),e("ember-routing-handlebars/helpers/render",["ember-metal/core","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/string","ember-routing/system/generate_controller","ember-handlebars/ext","ember-handlebars/helpers/view","exports"],function(e,t,r,n,i,a,s,o,u){"use strict";var l=(e["default"],t["default"]),c=(r.get,n.set,i.camelize),h=a.generateControllerFactory,p=a["default"],m=s.handlebarsGet,f=o.ViewHelper;u["default"]=function(e,t,r){var n,i,a,s,o,u=arguments.length;if(n=(r||t).data.keywords.controller.container,i=n.lookup("router:main"),2===u)r=t,t=void 0;else{if(3!==u)throw new l("You must pass a templateName to render");o=m(r.contexts[1],t,r)}e=e.replace(/\//g,"."),s=n.lookup("view:"+e)||n.lookup("view:default");var d=r.hash.controller||e,v="controller:"+d;r.hash.controller;var b=r.data.keywords.controller;if(u>2){var y=n.lookupFactory(v)||h(n,d,o);a=y.create({model:o,parentController:b,target:b}),s.one("willDestroyElement",function(){a.destroy()})}else a=n.lookup(v)||p(n,d),a.setProperties({target:b,parentController:b});var g=r.contexts[1];g&&s.registerObserver(g,t,function(){a.set("model",m(g,t,r))}),r.hash.viewName=c(e);var _="template:"+e;r.hash.template=n.lookup(_),r.hash.controller=a,i&&!o&&i._connectActiveView(e,s),r.helperName=r.helperName||'render "'+e+'"',f.instanceHelper(this,s,r)}}),e("ember-routing-handlebars/helpers/shared",["ember-metal/property_get","ember-metal/array","ember-runtime/mixins/controller","ember-handlebars/ext","ember-metal/utils","exports"],function(e,t,r,n,i,a){"use strict";function s(e,t,r){var n=[];return"string"===v(e)&&n.push(""+e),n.push.apply(n,t),n.push({queryParams:r}),n}function o(e){var t=e.activeTransition?e.activeTransition.state.handlerInfos:e.state.handlerInfos;return t[t.length-1].name}function u(e,t,r){return p.call(c(e,t,r),function(n,i){return null===n?t[i]:d(e,n,r)})}function l(e,t){if(!t._namesStashed){for(var r=t[t.length-1].name,n=e.router.recognizer.handlersFor(r),i=null,a=0,s=t.length;s>a;++a){var o=t[a],u=n[a].names;u.length&&(i=o),o._names=u;var l=o.handler;l._stashNames(o,i)}t._namesStashed=!0}}function c(e,t,r){function n(e,t){return"controller"===t?t:m.detect(e)?n(h(e,"model"),t?t+".model":"model"):t}var i=f(e,t,r),a=r.types;return p.call(i,function(e,r){return"ID"===a[r]?n(e,t[r]):null})}var h=e.get,p=t.map,m=r["default"],f=n.resolveParams,d=n.handlebarsGet,v=i.typeOf,h=e.get;a.routeArgs=s,a.getActiveTargetName=o,a.resolveParams=u,a.stashParamNames=l,a.resolvePaths=c}),e("ember-routing",["ember-handlebars","ember-metal/core","ember-routing/ext/run_loop","ember-routing/ext/controller","ember-routing/ext/view","ember-routing/location/api","ember-routing/location/none_location","ember-routing/location/hash_location","ember-routing/location/history_location","ember-routing/location/auto_location","ember-routing/system/generate_controller","ember-routing/system/controller_for","ember-routing/system/dsl","ember-routing/system/router","ember-routing/system/route","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m,f,d){"use strict";var v=(e["default"],t["default"]),b=a["default"],y=s["default"],g=o["default"],_=u["default"],w=l["default"],x=c.generateControllerFactory,C=c["default"],O=h["default"],E=p["default"],P=m["default"],A=f["default"];v.Location=b,v.AutoLocation=w,v.HashLocation=g,v.HistoryLocation=_,v.NoneLocation=y,v.controllerFor=O,v.generateControllerFactory=x,v.generateController=C,v.RouterDSL=E,v.Router=P,v.Route=A,d["default"]=v}),e("ember-routing/ext/controller",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/computed","ember-metal/utils","ember-metal/merge","ember-metal/enumerable_utils","ember-runtime/mixins/controller","exports"],function(e,t,r,n,i,a,s,o,u){"use strict";function l(e,t){var r,n=e;"string"===f(n)&&(r={},r[n]={as:null},n=r);for(var i in n){if(!n.hasOwnProperty(i))return;var a=n[i];"string"===f(a)&&(a={as:a}),r=t[i]||{as:null,scope:"model"},v(r,a),t[i]=r}}function c(e){var t=h(e,"_normalizedQueryParams");for(var r in t)t.hasOwnProperty(r)&&e.addObserver(r+".[]",e,e._qpChanged)}var h=(e["default"],t.get),p=r.set,m=n.computed,f=i.typeOf,d=i.meta,v=a["default"],b=(s.map,o["default"]);b.reopen({concatenatedProperties:["queryParams","_pCacheMeta"],init:function(){this._super.apply(this,arguments),c(this)},queryParams:null,_qpDelegate:null,_normalizedQueryParams:m(function(){var e=d(this);if(e.proto!==this)return h(e.proto,"_normalizedQueryParams");var t=h(this,"queryParams");if(t._qpMap)return t._qpMap;for(var r=t._qpMap={},n=0,i=t.length;i>n;++n)l(t[n],r);return r}),_cacheMeta:m(function(){var e=d(this);if(e.proto!==this)return h(e.proto,"_cacheMeta");var t={},r=h(this,"_normalizedQueryParams");for(var n in r)if(r.hasOwnProperty(n)){var i,a=r[n],s=a.scope;"controller"===s&&(i=[]),t[n]={parts:i,values:null,scope:s,prefix:"",def:h(this,n)}}return t}),_updateCacheParams:function(e){var t=h(this,"_cacheMeta");for(var r in t)if(t.hasOwnProperty(r)){var n=t[r];n.values=e;var i=this._calculateCacheKey(n.prefix,n.parts,n.values),a=this._bucketCache;if(a){var s=a.lookup(i,r,n.def);p(this,r,s)}}},_qpChanged:function(e,t){var r=t.substr(0,t.length-3),n=h(e,"_cacheMeta"),i=n[r],a=e._calculateCacheKey(i.prefix||"",i.parts,i.values),s=h(e,r),o=this._bucketCache;o&&e._bucketCache.stash(a,r,s);var u=e._qpDelegate;u&&u(e,r)},_calculateCacheKey:function(e,t,r){for(var n=t||[],i="",a=0,s=n.length;s>a;++a){var o=n[a],u=h(r,o);i+="::"+o+":"+u}return e+i.replace(y,"-")},transitionToRoute:function(){var e=h(this,"target"),t=e.transitionToRoute||e.transitionTo;return t.apply(e,arguments)},transitionTo:function(){return this.transitionToRoute.apply(this,arguments)},replaceRoute:function(){var e=h(this,"target"),t=e.replaceRoute||e.replaceWith;return t.apply(e,arguments)},replaceWith:function(){return this.replaceRoute.apply(this,arguments)}});var y=/\./g;u["default"]=b}),e("ember-routing/ext/run_loop",["ember-metal/run_loop"],function(e){"use strict";{var t=e["default"];t.queues}t._addQueue("routerTransitions","actions")}),e("ember-routing/ext/view",["ember-metal/property_get","ember-metal/property_set","ember-metal/run_loop","ember-views/views/view","exports"],function(e,t,r,n,i){"use strict";var a=e.get,s=t.set,o=r["default"],u=n["default"];u.reopen({init:function(){s(this,"_outlets",{}),this._super()},connectOutlet:function(e,t){if(this._pendingDisconnections&&delete this._pendingDisconnections[e],this._hasEquivalentView(e,t))return void t.destroy();var r=a(this,"_outlets"),n=a(this,"container"),i=n&&n.lookup("router:main"),o=a(t,"renderedName");s(r,e,t),i&&o&&i._connectActiveView(o,t)},_hasEquivalentView:function(e,t){var r=a(this,"_outlets."+e);return r&&r.constructor===t.constructor&&r.get("template")===t.get("template")&&r.get("context")===t.get("context")},disconnectOutlet:function(e){this._pendingDisconnections||(this._pendingDisconnections={}),this._pendingDisconnections[e]=!0,o.once(this,"_finishDisconnections")},_finishDisconnections:function(){if(!this.isDestroyed){var e=a(this,"_outlets"),t=this._pendingDisconnections;this._pendingDisconnections=null;for(var r in t)s(e,r,null)}}}),i["default"]=u}),e("ember-routing/location/api",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","exports"],function(e,t,r,n){"use strict";e["default"],t.get,r.set;n["default"]={create:function(e){var t=e&&e.implementation,r=this.implementations[t];return r.create.apply(r,arguments)},registerImplementation:function(e,t){this.implementations[e]=t},implementations:{},_location:window.location,_getHash:function(){var e=(this._location||this.location).href,t=e.indexOf("#");return-1===t?"":e.substr(t)}}}),e("ember-routing/location/auto_location",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-routing/location/api","ember-routing/location/history_location","ember-routing/location/hash_location","ember-routing/location/none_location","exports"],function(e,t,r,n,i,a,s,o){"use strict";var u=(e["default"],t.get,r.set),l=n["default"],c=i["default"],h=a["default"],p=s["default"];o["default"]={cancelRouterSetup:!1,rootURL:"/",_window:window,_location:window.location,_history:window.history,_HistoryLocation:c,_HashLocation:h,_NoneLocation:p,_getOrigin:function(){var e=this._location,t=e.origin; +return t||(t=e.protocol+"//"+e.hostname,e.port&&(t+=":"+e.port)),t},_getSupportsHistory:function(){var e=this._window.navigator.userAgent;return-1!==e.indexOf("Android 2")&&-1!==e.indexOf("Mobile Safari")&&-1===e.indexOf("Chrome")?!1:!!(this._history&&"pushState"in this._history)},_getSupportsHashChange:function(){var e=this._window,t=e.document.documentMode;return"onhashchange"in e&&(void 0===t||t>7)},_replacePath:function(e){this._location.replace(this._getOrigin()+e)},_getRootURL:function(){return this.rootURL},_getPath:function(){var e=this._location.pathname;return"/"!==e.charAt(0)&&(e="/"+e),e},_getHash:l._getHash,_getQuery:function(){return this._location.search},_getFullPath:function(){return this._getPath()+this._getQuery()+this._getHash()},_getHistoryPath:function(){{var e,t,r=this._getRootURL(),n=this._getPath(),i=this._getHash(),a=this._getQuery();n.indexOf(r)}return"#/"===i.substr(0,2)?(t=i.substr(1).split("#"),e=t.shift(),"/"===n.slice(-1)&&(e=e.substr(1)),n+=e,n+=a,t.length&&(n+="#"+t.join("#"))):(n+=a,n+=i),n},_getHashPath:function(){var e=this._getRootURL(),t=e,r=this._getHistoryPath(),n=r.substr(e.length);return""!==n&&("/"!==n.charAt(0)&&(n="/"+n),t+="#"+n),t},create:function(e){e&&e.rootURL&&(this.rootURL=e.rootURL);var t,r,n=!1,i=this._NoneLocation,a=this._getFullPath();this._getSupportsHistory()?(t=this._getHistoryPath(),a===t?i=this._HistoryLocation:"/#"===a.substr(0,2)?(this._history.replaceState({path:t},null,t),i=this._HistoryLocation):(n=!0,this._replacePath(t))):this._getSupportsHashChange()&&(r=this._getHashPath(),a===r||"/"===a&&"/#/"===r?i=this._HashLocation:(n=!0,this._replacePath(r)));var s=i.create.apply(i,arguments);return n&&u(s,"cancelRouterSetup",!0),s}}}),e("ember-routing/location/hash_location",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/run_loop","ember-metal/utils","ember-runtime/system/object","ember-routing/location/api","exports"],function(e,t,r,n,i,a,s,o){"use strict";var u=e["default"],l=t.get,c=r.set,h=n["default"],p=i.guidFor,m=a["default"],f=s["default"];o["default"]=m.extend({implementation:"hash",init:function(){c(this,"location",l(this,"_location")||window.location)},getHash:f._getHash,getURL:function(){var e=this.getHash().substr(1);return e},setURL:function(e){l(this,"location").hash=e,c(this,"lastSetURL",e)},replaceURL:function(e){l(this,"location").replace("#"+e),c(this,"lastSetURL",e)},onUpdateURL:function(e){var t=this,r=p(this);u.$(window).on("hashchange.ember-location-"+r,function(){h(function(){var r=t.getURL();l(t,"lastSetURL")!==r&&(c(t,"lastSetURL",null),e(r))})})},formatURL:function(e){return"#"+e},willDestroy:function(){var e=p(this);u.$(window).off("hashchange.ember-location-"+e)}})}),e("ember-routing/location/history_location",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-runtime/system/object","ember-views/system/jquery","exports"],function(e,t,r,n,i,a,s){"use strict";var o=(e["default"],t.get),u=r.set,l=n.guidFor,c=i["default"],h=a["default"],p=!1,m=window.history&&"state"in window.history;s["default"]=c.extend({implementation:"history",init:function(){u(this,"location",o(this,"location")||window.location),u(this,"baseURL",h("base").attr("href")||"")},initState:function(){u(this,"history",o(this,"history")||window.history),this.replaceState(this.formatURL(this.getURL()))},rootURL:"/",getURL:function(){var e=o(this,"rootURL"),t=o(this,"location"),r=t.pathname,n=o(this,"baseURL");e=e.replace(/\/$/,""),n=n.replace(/\/$/,"");var i=r.replace(n,"").replace(e,""),a=t.search||"";return i+=a},setURL:function(e){var t=this.getState();e=this.formatURL(e),t&&t.path===e||this.pushState(e)},replaceURL:function(e){var t=this.getState();e=this.formatURL(e),t&&t.path===e||this.replaceState(e)},getState:function(){return m?o(this,"history").state:this._historyState},pushState:function(e){var t={path:e};o(this,"history").pushState(t,null,e),m||(this._historyState=t),this._previousURL=this.getURL()},replaceState:function(e){var t={path:e};o(this,"history").replaceState(t,null,e),m||(this._historyState=t),this._previousURL=this.getURL()},onUpdateURL:function(e){var t=l(this),r=this;h(window).on("popstate.ember-location-"+t,function(){(p||(p=!0,r.getURL()!==r._previousURL))&&e(r.getURL())})},formatURL:function(e){var t=o(this,"rootURL"),r=o(this,"baseURL");return""!==e?(t=t.replace(/\/$/,""),r=r.replace(/\/$/,"")):r.match(/^\//)&&t.match(/^\//)&&(r=r.replace(/\/$/,"")),r+t+e},willDestroy:function(){var e=l(this);h(window).off("popstate.ember-location-"+e)}})}),e("ember-routing/location/none_location",["ember-metal/property_get","ember-metal/property_set","ember-runtime/system/object","exports"],function(e,t,r,n){"use strict";var i=e.get,a=t.set,s=r["default"];n["default"]=s.extend({implementation:"none",path:"",getURL:function(){return i(this,"path")},setURL:function(e){a(this,"path",e)},onUpdateURL:function(e){this.updateCallback=e},handleURL:function(e){a(this,"path",e),this.updateCallback(e)},formatURL:function(e){return e}})}),e("ember-routing/system/cache",["ember-runtime/system/object","exports"],function(e,t){"use strict";var r=e["default"];t["default"]=r.extend({init:function(){this.cache={}},has:function(e){return e in this.cache},stash:function(e,t,r){var n=this.cache[e];n||(n=this.cache[e]={}),n[t]=r},lookup:function(e,t,r){var n=this.cache;if(!(e in n))return r;var i=n[e];return t in i?i[t]:r},cache:null})}),e("ember-routing/system/controller_for",["exports"],function(e){"use strict";e["default"]=function(e,t,r){return e.lookup("controller:"+t,r)}}),e("ember-routing/system/dsl",["ember-metal/core","exports"],function(e,t){"use strict";function r(e){this.parent=e,this.matches=[]}function n(e){return e.parent&&"application"!==e.parent}function i(e,t,r){r=r||{},"string"!=typeof r.path&&(r.path="/"+t),n(e)&&r.resetNamespace!==!0&&(t=e.parent+"."+t),e.push(r.path,t,null)}e["default"];t["default"]=r,r.prototype={route:function(e,t,a){2===arguments.length&&"function"==typeof t&&(a=t,t={}),1===arguments.length&&(t={});t.resetNamespace===!0?"resource":"route";if("string"!=typeof t.path&&(t.path="/"+e),n(this)&&t.resetNamespace!==!0&&(e=this.parent+"."+e),a){var s=new r(e);i(s,"loading"),i(s,"error",{path:"/_unused_dummy_error_path_route_"+e+"/:error"}),a&&a.call(s),this.push(t.path,e,s.generate())}else this.push(t.path,e,null)},push:function(e,t,r){var n=t.split(".");(""===e||"/"===e||"index"===n[n.length-1])&&(this.explicitIndex=!0),this.matches.push([e,t,r])},resource:function(e,t,r){2===arguments.length&&"function"==typeof t&&(r=t,t={}),1===arguments.length&&(t={}),t.resetNamespace=!0,this.route(e,t,r)},generate:function(){var e=this.matches;return this.explicitIndex||i(this,"index",{path:"/"}),function(t){for(var r=0,n=e.length;n>r;r++){var i=e[r];t(i[0]).to(i[1],i[2])}}}},r.map=function(e){var t=new r;return e.call(t),t}}),e("ember-routing/system/generate_controller",["ember-metal/core","ember-metal/property_get","ember-metal/utils","exports"],function(e,t,r,n){"use strict";function i(e,t,r){var n,i,a,o;return o=r&&s(r)?"array":r?"object":"basic",a="controller:"+o,n=e.lookupFactory(a).extend({isGenerated:!0,toString:function(){return"(generated "+t+" controller)"}}),i="controller:"+t,e.register(i,n),n}var a=(e["default"],t.get),s=r.isArray;n.generateControllerFactory=i,n["default"]=function(e,t,r){i(e,t,r);var n="controller:"+t,s=e.lookup(n);return a(s,"namespace.LOG_ACTIVE_GENERATION"),s}}),e("ember-routing/system/route",["ember-metal/core","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/get_properties","ember-metal/enumerable_utils","ember-metal/is_none","ember-metal/computed","ember-metal/merge","ember-metal/utils","ember-metal/run_loop","ember-metal/keys","ember-runtime/copy","ember-runtime/system/string","ember-runtime/system/object","ember-runtime/mixins/action_handler","ember-routing/system/generate_controller","ember-routing-handlebars/helpers/shared","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m,f,d,v,b,y){"use strict";function g(e){var t=_(e,e.router.router.state.handlerInfos,-1);return t&&t.handler}function _(e,t,r){if(t)for(var n,i=r||0,a=0,s=t.length;s>a;a++)if(n=t[a].handler,n===e)return t[a+i]}function w(e){var t,r=g(e);if(r)return(t=r.lastRenderedTemplate)?t:w(r)}function x(e,t,r,n){n=n||{},n.into=n.into?n.into.replace(/\//g,"."):w(e),n.outlet=n.outlet||"main",n.name=t,n.template=r,n.LOG_VIEW_LOOKUPS=I(e.router,"namespace.LOG_VIEW_LOOKUPS");var i=n.controller,a=n.model;if(i=n.controller?n.controller:n.namePassed?e.container.lookup("controller:"+t)||e.controllerName||e.routeName:e.controllerName||e.container.lookup("controller:"+t),"string"==typeof i){var s=i;if(i=e.container.lookup("controller:"+s),!i)throw new V("You passed `controller: '"+s+"'` into the `render` method, but no such controller could be found.")}return a&&i.set("model",a),n.controller=i,n}function C(e,t,r){if(e)r.LOG_VIEW_LOOKUPS;else{var n=r.into?"view:default":"view:toplevel";e=t.lookup(n),r.LOG_VIEW_LOOKUPS}return I(e,"templateName")||(k(e,"template",r.template),k(e,"_debugTemplateName",r.name)),k(e,"renderedName",r.name),k(e,"controller",r.controller),e}function O(e,t,r){if(r.into){var n=e.router._lookupActiveView(r.into),i=P(n,r.outlet);e.teardownOutletViews||(e.teardownOutletViews=[]),M(e.teardownOutletViews,0,0,[i]),n.connectOutlet(r.outlet,t)}else{var a=I(e,"router.namespace.rootElement");e.teardownTopLevelView&&e.teardownTopLevelView(),e.router._connectActiveView(r.name,t),e.teardownTopLevelView=E(t),t.appendTo(a)}}function E(e){return function(){e.destroy()}}function P(e,t){return function(){e.disconnectOutlet(t)}}function A(e,t){if(t.fullQueryParams)return t.fullQueryParams;t.fullQueryParams={},L(t.fullQueryParams,t.queryParams);var r=t.handlerInfos[t.handlerInfos.length-1].name;return e._deserializeQueryParams(r,t.fullQueryParams),t.fullQueryParams}function T(e,t){t.queryParamsFor=t.queryParamsFor||{};var r=e.routeName;if(t.queryParamsFor[r])return t.queryParamsFor[r];for(var n=A(e.router,t),i=t.queryParamsFor[r]={},a=I(e,"_qp"),s=a.qps,o=0,u=s.length;u>o;++o){var l=s[o],c=l.prop in n;i[l.prop]=c?n[l.prop]:N(l.def)}return i}function N(e){return H(e)?S.A(e.slice()):e}var S=e["default"],V=t["default"],I=r.get,k=n.set,D=i["default"],j=a.forEach,M=a.replace,R=(s.isNone,o.computed),L=u["default"],H=l.isArray,z=l.typeOf,q=c["default"],F=h["default"],B=p["default"],U=(m.classify,m.fmt,f["default"]),K=d["default"],W=v["default"],G=b.stashParamNames,Q=U.extend(K,{queryParams:{},_qp:R(function(){var e=this.controllerName||this.routeName,t=this.container.lookupFactory("controller:"+e);if(!t)return $;var r=t.proto(),n=I(r,"_normalizedQueryParams"),i=I(r,"_cacheMeta"),a=[],s={},o=this;for(var u in n)if(n.hasOwnProperty(u)){var l=n[u],c=l.as||this.serializeQueryParamKey(u),h=I(r,u);H(h)&&(h=S.A(h.slice()));var p=z(h),m=this.serializeQueryParam(h,c,p),f=e+":"+u,d={def:h,sdef:m,type:p,urlKey:c,prop:u,fprop:f,ctrl:e,cProto:r,svalue:m,cacheType:l.scope,route:this,cacheMeta:i[u]};s[u]=s[c]=s[f]=d,a.push(d)}return{qps:a,map:s,states:{active:function(e,t){return o._activeQPChanged(e,s[t])},allowOverrides:function(e,t){return o._updatingQPChanged(e,s[t])},changingKeys:function(e,t){return o._updateSerializedQPValue(e,s[t])}}}}),_names:null,_stashNames:function(e,t){var r=e;if(!this._names){var n=this._names=r._names;n.length||(r=t,n=r&&r._names||[]);for(var i=I(this,"_qp.qps"),a=i.length,s=new Array(n.length),o=0,u=n.length;u>o;++o)s[o]=r.name+"."+n[o];for(var l=0;a>l;++l){var c=i[l],h=c.cacheMeta;"model"===h.scope&&(h.parts=s),h.prefix=c.ctrl}}},_updateSerializedQPValue:function(e,t){var r=I(e,t.prop);t.svalue=this.serializeQueryParam(r,t.urlKey,t.type)},_activeQPChanged:function(e,t){var r=I(e,t.prop);this.router._queuedQPChanges[t.fprop]=r,q.once(this,this._fireQueryParamTransition)},_updatingQPChanged:function(e,t){var r=this.router;r._qpUpdates||(r._qpUpdates={}),r._qpUpdates[t.urlKey]=!0},mergedProperties:["events","queryParams"],paramsFor:function(e){var t=this.container.lookup("route:"+e);if(!t)return{};var r=this.router.router.activeTransition,n=r?r.state:this.router.router.state,i={};return L(i,n.params[e]),L(i,T(t,n)),i},serializeQueryParamKey:function(e){return e},serializeQueryParam:function(e,t,r){return"array"===r?JSON.stringify(e):""+e},deserializeQueryParam:function(e,t,r){return"boolean"===r?"true"===e?!0:!1:"number"===r?Number(e).valueOf():"array"===r?S.A(JSON.parse(e)):e},_fireQueryParamTransition:function(){this.transitionTo({queryParams:this.router._queuedQPChanges}),this.router._queuedQPChanges={}},resetController:S.K,exit:function(){this.deactivate(),this.teardownViews()},_reset:function(e,t){var r=this.controller;r._qpDelegate=I(this,"_qp.states.inactive"),this.resetController(r,e,t)},enter:function(){this.activate()},viewName:null,templateName:null,controllerName:null,_actions:{queryParamsDidChange:function(e,t,r){for(var n=F(e).concat(F(r)),i=0,a=n.length;a>i;++i){var s=n[i],o=I(this.queryParams,s)||{};I(o,"refreshModel")&&this.refresh()}return!0},finalizeQueryParamChange:function(e,t,r){if("application"!==this.routeName)return!0;if(r){var n,i=r.state.handlerInfos,a=this.router,s=a._queryParamsFor(i[i.length-1].name),o=a._qpUpdates;G(a,i);for(var u=0,l=s.qps.length;l>u;++u){var c,h,p=s.qps[u],m=p.route,f=m.controller,d=p.urlKey in e&&p.urlKey;o&&p.urlKey in o?(c=I(f,p.prop),h=m.serializeQueryParam(c,p.urlKey,p.type)):d?(h=e[d],c=m.deserializeQueryParam(h,p.urlKey,p.type)):(h=p.sdef,c=N(p.def)),f._qpDelegate=I(this,"_qp.states.inactive");var v=h!==p.svalue;if(v){var b=I(m,"queryParams."+p.urlKey)||{};if(r.queryParamsOnly&&n!==!1){var y=I(b,"replace");y?n=!0:y===!1&&(n=!1)}k(f,p.prop,c)}p.svalue=h;var g=p.sdef===h;g||t.push({value:h,visible:!0,key:d||p.urlKey})}n&&r.method("replace"),j(s.qps,function(e){var t=I(e.route,"_qp"),r=e.route.controller;r._qpDelegate=I(t,"states.active")}),a._qpUpdates=null}}},events:null,deactivate:S.K,activate:S.K,transitionTo:function(){var e=this.router;return e.transitionTo.apply(e,arguments)},intermediateTransitionTo:function(){var e=this.router;e.intermediateTransitionTo.apply(e,arguments)},refresh:function(){return this.router.router.refresh(this)},replaceWith:function(){var e=this.router;return e.replaceWith.apply(e,arguments)},send:function(){return this.router.send.apply(this.router,arguments)},setup:function(e,t){var r=this.controllerName||this.routeName,n=this.controllerFor(r,!0);if(n||(n=this.generateController(r,e)),this.controller=n,this.setupControllers)this.setupControllers(n,e);else{var i=I(this,"_qp.states");if(t&&(G(this.router,t.state.handlerInfos),n._qpDelegate=i.changingKeys,n._updateCacheParams(t.params)),n._qpDelegate=i.allowOverrides,t){var a=T(this,t.state);n.setProperties(a)}this.setupController(n,e,t)}this.renderTemplates?this.renderTemplates(e):this.renderTemplate(n,e)},beforeModel:S.K,afterModel:S.K,redirect:S.K,contextDidChange:function(){this.currentModel=this.context},model:function(e,t){var r,n,i,a,s=I(this,"_qp.map");for(var o in e)"queryParams"===o||s&&o in s||((r=o.match(/^(.*)_id$/))&&(n=r[1],a=e[o]),i=!0);if(!n&&i)return B(e);if(!n){if(t.resolveIndex<1)return;var u=t.state.handlerInfos[t.resolveIndex-1].context;return u}return this.findModel(n,a)},deserialize:function(e,t){return this.model(this.paramsFor(this.routeName),t)},findModel:function(){var e=I(this,"store");return e.find.apply(e,arguments)},store:R(function(){{var e=this.container;this.routeName,I(this,"router.namespace")}return{find:function(t,r){var n=e.lookupFactory("model:"+t);if(n)return n.find(r)}}}),serialize:function(e,t){if(!(t.length<1)&&e){var r=t[0],n={};return/_id$/.test(r)&&1===t.length?n[r]=I(e,"id"):n=D(e,t),n}},setupController:function(e,t){e&&void 0!==t&&k(e,"model",t)},controllerFor:function(e){var t,r=this.container,n=r.lookup("route:"+e);return n&&n.controllerName&&(e=n.controllerName),t=r.lookup("controller:"+e)},generateController:function(e,t){var r=this.container;return t=t||this.modelFor(e),W(r,e,t)},modelFor:function(e){var t=this.container.lookup("route:"+e),r=this.router?this.router.router.activeTransition:null;if(r){var n=t&&t.routeName||e;if(r.resolvedModels.hasOwnProperty(n))return r.resolvedModels[n]}return t&&t.currentModel},renderTemplate:function(){this.render()},render:function(e,t){var r="string"==typeof e&&!!e;"object"!=typeof e||t||(t=e,e=this.routeName),t=t||{},t.namePassed=r;var n;e?(e=e.replace(/\//g,"."),n=e):(e=this.routeName,n=this.templateName||e);var i=t.view||r&&e||this.viewName||e,a=this.container,s=a.lookup("view:"+i),o=s?s.get("template"):null;return o||(o=a.lookup("template:"+n)),s||o?(t=x(this,e,o,t),s=C(s,a,t),"main"===t.outlet&&(this.lastRenderedTemplate=e),void O(this,s,t)):void I(this.router,"namespace.LOG_VIEW_LOOKUPS")},disconnectOutlet:function(e){if(!e||"string"==typeof e){var t=e;e={},e.outlet=t}e.parentView=e.parentView?e.parentView.replace(/\//g,"."):w(this),e.outlet=e.outlet||"main";var r=this.router._lookupActiveView(e.parentView);r&&r.disconnectOutlet(e.outlet)},willDestroy:function(){this.teardownViews()},teardownViews:function(){this.teardownTopLevelView&&this.teardownTopLevelView();var e=this.teardownOutletViews||[];j(e,function(e){e()}),delete this.teardownTopLevelView,delete this.teardownOutletViews,delete this.lastRenderedTemplate}}),$={qps:[],map:{},states:{}};y["default"]=Q}),e("ember-routing/system/router",["ember-metal/core","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/properties","ember-metal/computed","ember-metal/merge","ember-metal/run_loop","ember-metal/enumerable_utils","ember-runtime/system/string","ember-runtime/system/object","ember-runtime/mixins/evented","ember-routing/system/dsl","ember-views/views/view","ember-routing/location/api","ember-handlebars/views/metamorph_view","ember-routing-handlebars/helpers/shared","ember-metal/platform","exports"],function(e,r,n,i,a,s,o,u,l,c,h,p,m,f,d,v,b,y,g){"use strict";function _(e,t,r){for(var n,i,a=t.state.handlerInfos,s=!1,o=a.length-1;o>=0;--o)if(n=a[o],i=n.handler,s){if(r(i,a[o+1].handler)!==!0)return!1}else e===i&&(s=!0);return!0}function w(e,t){var r=[];t&&r.push(t),e&&(e.message&&r.push(e.message),e.stack&&r.push(e.stack),"string"==typeof e&&r.push(e)),S.Logger.error.apply(this,r)}function x(e,t,r){var n,i=e.router,a=(t.routeName.split(".").pop(),"application"===e.routeName?"":e.routeName+".");return n=a+r,C(i,n)?n:void 0}function C(e,t){var r=e.container;return e.hasRoute(t)&&(r.has("template:"+t)||r.has("route:"+t))}function O(e,t,r){var n=r.shift();if(!e){if(t)return;throw new V("Can't trigger action '"+n+"' because your app hasn't finished transitioning into its first route. To trigger an action on destination routes during a transition, you can call `.send()` on the `Transition` object passed to the `model/beforeModel/afterModel` hooks.")}for(var i,a,s=!1,o=e.length-1;o>=0;o--)if(i=e[o],a=i.handler,a._actions&&a._actions[n]){if(a._actions[n].apply(a,r)!==!0)return;s=!0}if(Y[n])return void Y[n].apply(null,r);if(!s&&!t)throw new V("Nothing handled the action '"+n+"'. If you did handle the action, this error can be caused by returning true from an action handler in a controller, causing the action to bubble.")}function E(e,t,r){for(var n=e.router,i=n.applyIntent(t,r),a=i.handlerInfos,s=i.params,o=0,u=a.length;u>o;++o){var l=a[o];l.isResolved||(l=l.becomeResolved(null,l.context)),s[l.name]=l.params}return i}function P(e){var t=e.container.lookup("controller:application");if(t){var r=e.router.currentHandlerInfos,n=$._routePath(r);"currentPath"in t||D(t,"currentPath"),k(t,"currentPath",n),"currentRouteName"in t||D(t,"currentRouteName"),k(t,"currentRouteName",r[r.length-1].name)}}function A(e){e.then(null,function(e){return e&&e.name?("UnrecognizedURLError"===e.name,e):void 0},"Ember: Process errors from Router")}function T(e){return"string"==typeof e&&(""===e||"/"===e.charAt(0))}function N(e,t,r,n){{var i=e._queryParamsFor(t);i.qps}for(var a in r)if(r.hasOwnProperty(a)){var s=r[a],o=i.map[a];o&&n(a,s,o)}}var S=e["default"],V=r["default"],I=n.get,k=i.set,D=a.defineProperty,j=s.computed,M=o["default"],R=u["default"],L=(l.forEach,c.fmt,h["default"]),H=p["default"],z=m["default"],q=f["default"],F=d["default"],B=v["default"],U=b.routeArgs,K=b.getActiveTargetName,W=b.stashParamNames,G=(y.create,t("router")["default"]),Q=(t("router/transition").Transition,[].slice),$=L.extend(H,{location:"hash",rootURL:"/",init:function(){this.router=this.constructor.router||this.constructor.map(S.K),this._activeViews={},this._setupLocation(),this._qpCache={},this._queuedQPChanges={},I(this,"namespace.LOG_TRANSITIONS_INTERNAL")&&(this.router.log=S.Logger.debug)},url:j(function(){return I(this,"location").getURL()}),startRouting:function(){this.router=this.router||this.constructor.map(S.K);var e=this.router,t=I(this,"location"),r=this.container,n=this,i=I(this,"initialURL");I(t,"cancelRouterSetup")||(this._setupRouter(e,t),r.register("view:default",B),r.register("view:toplevel",q.extend()),t.onUpdateURL(function(e){n.handleURL(e)}),"undefined"==typeof i&&(i=t.getURL()),this.handleURL(i))},didTransition:function(e){P(this),this._cancelLoadingEvent(),this.notifyPropertyChange("url"),R.once(this,this.trigger,"didTransition"),I(this,"namespace").LOG_TRANSITIONS&&S.Logger.log("Transitioned into '"+$._routePath(e)+"'")},handleURL:function(e){return this._doURLTransition("handleURL",e)},_doURLTransition:function(e,t){var r=this.router[e](t||"/");return A(r),r},transitionTo:function(){var e,t=Q.call(arguments);if(T(t[0]))return this._doURLTransition("transitionTo",t[0]);var r=t[t.length-1];e=r&&r.hasOwnProperty("queryParams")?t.pop().queryParams:{};var n=t.shift();return this._doTransition(n,t,e)},intermediateTransitionTo:function(){this.router.intermediateTransitionTo.apply(this.router,arguments),P(this);var e=this.router.currentHandlerInfos;I(this,"namespace").LOG_TRANSITIONS&&S.Logger.log("Intermediate-transitioned into '"+$._routePath(e)+"'")},replaceWith:function(){return this.transitionTo.apply(this,arguments).method("replace")},generate:function(){var e=this.router.generate.apply(this.router,arguments);return this.location.formatURL(e)},isActive:function(){var e=this.router;return e.isActive.apply(e,arguments)},isActiveIntent:function(){var e=this.router;return e.isActive.apply(e,arguments)},send:function(){this.router.trigger.apply(this.router,arguments)},hasRoute:function(e){return this.router.hasRoute(e)},reset:function(){this.router.reset()},_lookupActiveView:function(e){var t=this._activeViews[e];return t&&t[0]},_connectActiveView:function(e,t){function r(){delete this._activeViews[e]}var n=this._activeViews[e];n&&n[0].off("willDestroyElement",this,n[1]),this._activeViews[e]=[t,r],t.one("willDestroyElement",this,r)},_setupLocation:function(){var e=I(this,"location"),t=I(this,"rootURL");if(t&&this.container&&!this.container.has("-location-setting:root-url")&&this.container.register("-location-setting:root-url",t,{instantiate:!1}),"string"==typeof e&&this.container){var r=this.container.lookup("location:"+e);if("undefined"!=typeof r)e=k(this,"location",r);else{var n={implementation:e};e=k(this,"location",F.create(n))}}null!==e&&"object"==typeof e&&(t&&"string"==typeof t&&(e.rootURL=t),"function"==typeof e.initState&&e.initState())},_getHandlerFunction:function(){var e={},t=this.container,r=t.lookupFactory("route:basic"),n=this;return function(i){var a="route:"+i,s=t.lookup(a);return e[i]?s:(e[i]=!0,s||(t.register(a,r.extend()),s=t.lookup(a),I(n,"namespace.LOG_ACTIVE_GENERATION")),s.routeName=i,s)}},_setupRouter:function(e,t){var r,n=this;e.getHandler=this._getHandlerFunction();var i=function(){t.setURL(r)};if(e.updateURL=function(e){r=e,R.once(i)},t.replaceURL){var a=function(){t.replaceURL(r)};e.replaceURL=function(e){r=e,R.once(a)}}e.didTransition=function(e){n.didTransition(e)}},_serializeQueryParams:function(e,t){var r={};N(this,e,t,function(e,n,i){var a=i.urlKey;r[a]||(r[a]=[]),r[a].push({qp:i,value:n}),delete t[e]});for(var n in r){var i=r[n];if(i.length>1){i[0].qp,i[1].qp}var a=i[0].qp;t[a.urlKey]=a.route.serializeQueryParam(i[0].value,a.urlKey,a.type)}},_deserializeQueryParams:function(e,t){N(this,e,t,function(e,r,n){delete t[e],t[n.prop]=n.route.deserializeQueryParam(r,n.urlKey,n.type)})},_pruneDefaultQueryParamValues:function(e,t){var r=this._queryParamsFor(e);for(var n in t){var i=r.map[n];i&&i.sdef===t[n]&&delete t[n]}},_doTransition:function(e,t,r){var n=e||K(this.router),i={};M(i,r),this._prepareQueryParams(n,t,i);var a=U(n,t,i),s=this.router.transitionTo.apply(this.router,a);return A(s),s},_prepareQueryParams:function(e,t,r){this._hydrateUnsuppliedQueryParams(e,t,r),this._serializeQueryParams(e,r),this._pruneDefaultQueryParamValues(e,r)},_queryParamsFor:function(e){if(this._qpCache[e])return this._qpCache[e];for(var t={},r=[],n=(this._qpCache[e]={map:t,qps:r},this.router),i=n.recognizer.handlersFor(e),a=0,s=i.length;s>a;++a){var o=i[a],u=n.getHandler(o.handler),l=I(u,"_qp");l&&(M(t,l.map),r.push.apply(r,l.qps))}return{qps:r,map:t}},_hydrateUnsuppliedQueryParams:function(e,t,r){var n=E(this,e,t),i=n.handlerInfos,a=this._bucketCache;W(this,i);for(var s=0,o=i.length;o>s;++s)for(var u=i[s].handler,l=I(u,"_qp"),c=0,h=l.qps.length;h>c;++c){var p=l.qps[c],m=p.prop in r&&p.prop||p.fprop in r&&p.fprop;if(m)m!==p.fprop&&(r[p.fprop]=r[m],delete r[m]);else{var f=p.cProto,d=I(f,"_cacheMeta"),v=f._calculateCacheKey(p.ctrl,d[p.prop].parts,n.params);r[p.fprop]=a.lookup(v,p.prop,p.def)}}},_scheduleLoadingEvent:function(e,t){this._cancelLoadingEvent(),this._loadingStateTimer=R.scheduleOnce("routerTransitions",this,"_fireLoadingEvent",e,t)},_fireLoadingEvent:function(e,t){this.router.activeTransition&&e.trigger(!0,"loading",e,t)},_cancelLoadingEvent:function(){this._loadingStateTimer&&R.cancel(this._loadingStateTimer),this._loadingStateTimer=null}}),Y={willResolveModel:function(e,t){t.router._scheduleLoadingEvent(e,t)},error:function(e,t,r){var n=r.router,i=_(r,t,function(t,r){var i=x(t,r,"error");return i?void n.intermediateTransitionTo(i,e):!0});return i&&C(r.router,"application_error")?void n.intermediateTransitionTo("application_error",e):void w(e,"Error while processing route: "+t.targetName)},loading:function(e,t){var r=t.router,n=_(t,e,function(t,n){var i=x(t,n,"loading");return i?void r.intermediateTransitionTo(i):e.pivotHandler!==t?!0:void 0});return n&&C(t.router,"application_loading")?void r.intermediateTransitionTo("application_loading"):void 0}};$.reopenClass({router:null,map:function(e){var t=this.router;t||(t=new G,t._triggerWillChangeContext=S.K,t._triggerWillLeave=S.K,t.callbacks=[],t.triggerEvent=O,this.reopenClass({router:t}));var r=z.map(function(){this.resource("application",{path:"/"},function(){for(var r=0;rr;++r)if(e[r]!==t[r])return!1;return!0}for(var r,n,i,a=[],s=1,o=e.length;o>s;s++){for(r=e[s].name,n=r.split("."),i=Q.call(a);i.length&&!t(i,n);)i.shift();a.push.apply(a,n.slice(i.length))}return a.join(".")}}),g["default"]=$}),e("ember-runtime",["ember-metal","ember-runtime/core","ember-runtime/compare","ember-runtime/copy","ember-runtime/system/namespace","ember-runtime/system/object","ember-runtime/system/tracked_array","ember-runtime/system/subarray","ember-runtime/system/container","ember-runtime/system/application","ember-runtime/system/array_proxy","ember-runtime/system/object_proxy","ember-runtime/system/core_object","ember-runtime/system/each_proxy","ember-runtime/system/native_array","ember-runtime/system/set","ember-runtime/system/string","ember-runtime/system/deferred","ember-runtime/system/lazy_load","ember-runtime/mixins/array","ember-runtime/mixins/comparable","ember-runtime/mixins/copyable","ember-runtime/mixins/enumerable","ember-runtime/mixins/freezable","ember-runtime/mixins/-proxy","ember-runtime/mixins/observable","ember-runtime/mixins/action_handler","ember-runtime/mixins/deferred","ember-runtime/mixins/mutable_enumerable","ember-runtime/mixins/mutable_array","ember-runtime/mixins/target_action_support","ember-runtime/mixins/evented","ember-runtime/mixins/promise_proxy","ember-runtime/mixins/sortable","ember-runtime/computed/array_computed","ember-runtime/computed/reduce_computed","ember-runtime/computed/reduce_computed_macros","ember-runtime/controllers/array_controller","ember-runtime/controllers/object_controller","ember-runtime/controllers/controller","ember-runtime/mixins/controller","ember-runtime/ext/rsvp","ember-runtime/ext/string","ember-runtime/ext/function","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m,f,d,v,b,y,g,_,w,x,C,O,E,P,A,T,N,S,V,I,k,D,j,M,R,L,H,z,q,F,B,U){"use strict";var K=e["default"],W=t.isEqual,G=r["default"],Q=n["default"],$=i["default"],Y=a["default"],J=s["default"],Z=o["default"],X=u["default"],et=(l["default"],c["default"]),tt=h["default"],rt=p["default"],nt=m.EachArray,it=m.EachProxy,at=f["default"],st=d["default"],ot=v["default"],ut=b["default"],lt=y.onLoad,ct=y.runLoadHooks,ht=g["default"],pt=_["default"],mt=w["default"],ft=x["default"],dt=C.Freezable,vt=C.FROZEN_ERROR,bt=O["default"],yt=E["default"],gt=P["default"],_t=A["default"],wt=T["default"],xt=N["default"],Ct=S["default"],Ot=V["default"],Et=I["default"],Pt=k["default"],At=D.arrayComputed,Tt=D.ArrayComputedProperty,Nt=j.reduceComputed,St=j.ReduceComputedProperty,Vt=M.sum,It=M.min,kt=M.max,Dt=M.map,jt=M.sort,Mt=M.setDiff,Rt=M.mapBy,Lt=M.mapProperty,Ht=M.filter,zt=M.filterBy,qt=M.filterProperty,Ft=M.uniq,Bt=M.union,Ut=M.intersect,Kt=R["default"],Wt=L["default"],Gt=H["default"],Qt=z["default"],$t=q["default"];K.compare=G,K.copy=Q,K.isEqual=W,K.Array=ht,K.Comparable=pt,K.Copyable=mt,K.SortableMixin=Pt,K.Freezable=dt,K.FROZEN_ERROR=vt,K.DeferredMixin=_t,K.MutableEnumerable=wt,K.MutableArray=xt,K.TargetActionSupport=Ct,K.Evented=Ot,K.PromiseProxyMixin=Et,K.Observable=yt,K.arrayComputed=At,K.ArrayComputedProperty=Tt,K.reduceComputed=Nt,K.ReduceComputedProperty=St;var Yt=K.computed;Yt.sum=Vt,Yt.min=It,Yt.max=kt,Yt.map=Dt,Yt.sort=jt,Yt.setDiff=Mt,Yt.mapBy=Rt,Yt.mapProperty=Lt,Yt.filter=Ht,Yt.filterBy=zt,Yt.filterProperty=qt,Yt.uniq=Ft,Yt.union=Bt,Yt.intersect=Ut,K.String=ot,K.Object=Y,K.TrackedArray=J,K.SubArray=Z,K.Container=X,K.Namespace=$,K.Enumerable=ft,K.ArrayProxy=et,K.ObjectProxy=tt,K.ActionHandler=gt,K.CoreObject=rt,K.EachArray=nt,K.EachProxy=it,K.NativeArray=at,K.Set=st,K.Deferred=ut,K.onLoad=lt,K.runLoadHooks=ct,K.ArrayController=Kt,K.ObjectController=Wt,K.Controller=Gt,K.ControllerMixin=Qt,K._ProxyMixin=bt,K.RSVP=$t,U["default"]=K}),e("ember-runtime/compare",["ember-metal/utils","ember-runtime/mixins/comparable","exports"],function(e,t,r){"use strict";function n(e,t){var r=e-t;return(r>0)-(0>r)}var i=e.typeOf,a=t["default"],s={undefined:0,"null":1,"boolean":2,number:3,string:4,array:5,object:6,instance:7,"function":8,"class":9,date:10};r["default"]=function o(e,t){if(e===t)return 0;var r=i(e),u=i(t);if(a){if("instance"===r&&a.detect(e.constructor))return e.constructor.compare(e,t);if("instance"===u&&a.detect(t.constructor))return 1-t.constructor.compare(t,e)}var l=n(s[r],s[u]);if(0!==l)return l;switch(r){case"boolean":case"number":return n(e,t);case"string":return n(e.localeCompare(t),0);case"array":for(var c=e.length,h=t.length,p=Math.min(c,h),m=0;p>m;m++){var f=o(e[m],t[m]);if(0!==f)return f}return n(c,h);case"instance":return a&&a.detect(e)?e.compare(e,t):0;case"date":return n(e.getTime(),t.getTime());default:return 0}}}),e("ember-runtime/computed/array_computed",["ember-metal/core","ember-runtime/computed/reduce_computed","ember-metal/enumerable_utils","ember-metal/platform","ember-metal/observer","ember-metal/error","exports"],function(e,t,r,n,i,a,s){"use strict";function o(){var e=this;return c.apply(this,arguments),this.func=function(t){return function(r){return e._hasInstanceMeta(this,r)||h(e._dependentKeys,function(t){m(this,t,function(){e.recomputeOnce.call(this,r) +})},this),t.apply(this,arguments)}}(this.func),this}function u(e){var t;if(arguments.length>1&&(t=d.call(arguments,0,-1),e=d.call(arguments,-1)[0]),"object"!=typeof e)throw new f("Array Computed Property declared without an options hash");var r=new o(e);return t&&r.property.apply(r,t),r}var l=e["default"],c=(t.reduceComputed,t.ReduceComputedProperty),h=r.forEach,p=n.create,m=i.addObserver,f=a["default"],d=[].slice;o.prototype=p(c.prototype),o.prototype.initialValue=function(){return l.A()},o.prototype.resetValue=function(e){return e.clear(),e},o.prototype.didChange=function(){},s.arrayComputed=u,s.ArrayComputedProperty=o}),e("ember-runtime/computed/reduce_computed",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/error","ember-metal/property_events","ember-metal/expand_properties","ember-metal/observer","ember-metal/computed","ember-metal/platform","ember-metal/enumerable_utils","ember-runtime/system/tracked_array","ember-runtime/mixins/array","ember-metal/run_loop","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m,f){"use strict";function d(e,t){return"@this"===t?e:T(e,t)}function v(e,t,r){this.callbacks=e,this.cp=t,this.instanceMeta=r,this.dependentKeysByGuid={},this.trackedArraysByGuid={},this.suspended=!1,this.changedItems={},this.changedItemCount=0}function b(e,t,r){this.dependentArray=e,this.index=t,this.item=e.objectAt(t),this.trackedArray=r,this.beforeObserver=null,this.observer=null,this.destroyed=!1}function y(e,t,r){return 0>e?Math.max(0,t+e):t>e?e:Math.min(t-r,e)}function g(e,t,r){return Math.min(r,t-e)}function _(e,t,r,n,i,a,s){this.arrayChanged=e,this.index=r,this.item=t,this.propertyName=n,this.property=i,this.changedCount=a,s&&(this.previousValues=s)}function w(e,t,r,n,i){F(e,function(a,s){i.setValue(t.addedItem.call(this,i.getValue(),a,new _(e,a,s,n,r,e.length),i.sugarMeta))},this),t.flushedChanges.call(this,i.getValue(),i.sugarMeta)}function x(e,t){var r=(e._callbacks(),e._hasInstanceMeta(this,t)),n=e._instanceMeta(this,t);r&&n.setValue(e.resetValue(n.getValue())),e.options.initialize&&e.options.initialize.call(this,n.getValue(),{property:e,propertyName:t},n.sugarMeta)}function C(e,t){if(Z.test(t))return!1;var r=d(e,t);return U.detect(r)}function O(e,t,r){this.context=e,this.propertyName=t,this.cache=S(e).cache,this.dependentArrays={},this.sugarMeta={},this.initialValue=r}function E(e){var t=this;this.options=e,this._dependentKeys=null,this._itemPropertyKeys={},this._previousItemPropertyKeys={},this.readOnly(),this.cacheable(),this.recomputeOnce=function(e){K.once(this,r,e)};var r=function(e){var r=(t._dependentKeys,t._instanceMeta(this,e)),n=t._callbacks();x.call(this,t,e),r.dependentArraysObserver.suspendArrayObservers(function(){F(t._dependentKeys,function(e){if(C(this,e)){var n=d(this,e),i=r.dependentArrays[e];n===i?t._previousItemPropertyKeys[e]&&(delete t._previousItemPropertyKeys[e],r.dependentArraysObserver.setupPropertyObservers(e,t._itemPropertyKeys[e])):(r.dependentArrays[e]=n,i&&r.dependentArraysObserver.teardownObservers(i,e),n&&r.dependentArraysObserver.setupObservers(n,e))}},this)},this),F(t._dependentKeys,function(i){if(C(this,i)){var a=d(this,i);a&&w.call(this,a,n,t,e,r)}},this)};this.func=function(e){return r.call(this,e),t._instanceMeta(this,e).getValue()}}function P(e){return e}function A(e){var t;if(arguments.length>1&&(t=$.call(arguments,0,-1),e=$.call(arguments,-1)[0]),"object"!=typeof e)throw new V("Reduce Computed Property declared without an options hash");if(!("initialValue"in e))throw new V("Reduce Computed Property declared without an initial value");var r=new E(e);return t&&r.property.apply(r,t),r}var T=(e["default"],t.get),N=(r.set,n.guidFor),S=n.meta,V=i["default"],I=a.propertyWillChange,k=a.propertyDidChange,D=s["default"],j=o.addObserver,M=(o.observersFor,o.removeObserver),R=o.addBeforeObserver,L=o.removeBeforeObserver,H=u.ComputedProperty,z=u.cacheFor,q=l.create,F=c.forEach,B=h["default"],U=p["default"],K=m["default"],W=(n.isArray,z.set),G=z.get,Q=z.remove,$=[].slice,Y=/^(.*)\.@each\.(.*)/,J=/(.*\.@each){2,}/,Z=/\.\[\]$/;v.prototype={setValue:function(e){this.instanceMeta.setValue(e,!0)},getValue:function(){return this.instanceMeta.getValue()},setupObservers:function(e,t){this.dependentKeysByGuid[N(e)]=t,e.addArrayObserver(this,{willChange:"dependentArrayWillChange",didChange:"dependentArrayDidChange"}),this.cp._itemPropertyKeys[t]&&this.setupPropertyObservers(t,this.cp._itemPropertyKeys[t])},teardownObservers:function(e,t){var r=this.cp._itemPropertyKeys[t]||[];delete this.dependentKeysByGuid[N(e)],this.teardownPropertyObservers(t,r),e.removeArrayObserver(this,{willChange:"dependentArrayWillChange",didChange:"dependentArrayDidChange"})},suspendArrayObservers:function(e,t){var r=this.suspended;this.suspended=!0,e.call(t),this.suspended=r},setupPropertyObservers:function(e,t){var r=d(this.instanceMeta.context,e),n=d(r,"length"),i=new Array(n);this.resetTransformations(e,i),F(r,function(n,a){var s=this.createPropertyObserverContext(r,a,this.trackedArraysByGuid[e]);i[a]=s,F(t,function(e){R(n,e,this,s.beforeObserver),j(n,e,this,s.observer)},this)},this)},teardownPropertyObservers:function(e,t){var r,n,i,a=this,s=this.trackedArraysByGuid[e];s&&s.apply(function(e,s,o){o!==B.DELETE&&F(e,function(e){e.destroyed=!0,r=e.beforeObserver,n=e.observer,i=e.item,F(t,function(e){L(i,e,a,r),M(i,e,a,n)})})})},createPropertyObserverContext:function(e,t,r){var n=new b(e,t,r);return this.createPropertyObserver(n),n},createPropertyObserver:function(e){var t=this;e.beforeObserver=function(r,n){return t.itemPropertyWillChange(r,n,e.dependentArray,e)},e.observer=function(r,n){return t.itemPropertyDidChange(r,n,e.dependentArray,e)}},resetTransformations:function(e,t){this.trackedArraysByGuid[e]=new B(t)},trackAdd:function(e,t,r){var n=this.trackedArraysByGuid[e];n&&n.addItems(t,r)},trackRemove:function(e,t,r){var n=this.trackedArraysByGuid[e];return n?n.removeItems(t,r):[]},updateIndexes:function(e,t){var r=d(t,"length");e.apply(function(e,t,n,i){n!==B.DELETE&&(0!==i||n!==B.RETAIN||e.length!==r||0!==t)&&F(e,function(e,r){e.index=r+t})})},dependentArrayWillChange:function(e,t,r){function n(e){u[o].destroyed=!0,L(a,e,this,u[o].beforeObserver),M(a,e,this,u[o].observer)}if(!this.suspended){var i,a,s,o,u,l=this.callbacks.removedItem,c=N(e),h=this.dependentKeysByGuid[c],p=this.cp._itemPropertyKeys[h]||[],m=d(e,"length"),f=y(t,m,0),v=g(f,m,r);for(u=this.trackRemove(h,f,v),o=v-1;o>=0&&(s=f+o,!(s>=m));--o)a=e.objectAt(s),F(p,n,this),i=new _(e,a,s,this.instanceMeta.propertyName,this.cp,v),this.setValue(l.call(this.instanceMeta.context,this.getValue(),a,i,this.instanceMeta.sugarMeta));this.callbacks.flushedChanges.call(this.instanceMeta.context,this.getValue(),this.instanceMeta.sugarMeta)}},dependentArrayDidChange:function(e,t,r,n){if(!this.suspended){var i,a,s=this.callbacks.addedItem,o=N(e),u=this.dependentKeysByGuid[o],l=new Array(n),c=this.cp._itemPropertyKeys[u],h=d(e,"length"),p=y(t,h,n),m=p+n;F(e.slice(p,m),function(t,r){c&&(a=this.createPropertyObserverContext(e,p+r,this.trackedArraysByGuid[u]),l[r]=a,F(c,function(e){R(t,e,this,a.beforeObserver),j(t,e,this,a.observer)},this)),i=new _(e,t,p+r,this.instanceMeta.propertyName,this.cp,n),this.setValue(s.call(this.instanceMeta.context,this.getValue(),t,i,this.instanceMeta.sugarMeta))},this),this.callbacks.flushedChanges.call(this.instanceMeta.context,this.getValue(),this.instanceMeta.sugarMeta),this.trackAdd(u,p,l)}},itemPropertyWillChange:function(e,t,r,n){var i=N(e);this.changedItems[i]||(this.changedItems[i]={array:r,observerContext:n,obj:e,previousValues:{}}),++this.changedItemCount,this.changedItems[i].previousValues[t]=d(e,t)},itemPropertyDidChange:function(){0===--this.changedItemCount&&this.flushChanges()},flushChanges:function(){var e,t,r,n=this.changedItems;for(e in n)t=n[e],t.observerContext.destroyed||(this.updateIndexes(t.observerContext.trackedArray,t.observerContext.dependentArray),r=new _(t.array,t.obj,t.observerContext.index,this.instanceMeta.propertyName,this.cp,n.length,t.previousValues),this.setValue(this.callbacks.removedItem.call(this.instanceMeta.context,this.getValue(),t.obj,r,this.instanceMeta.sugarMeta)),this.setValue(this.callbacks.addedItem.call(this.instanceMeta.context,this.getValue(),t.obj,r,this.instanceMeta.sugarMeta)));this.changedItems={},this.callbacks.flushedChanges.call(this.instanceMeta.context,this.getValue(),this.instanceMeta.sugarMeta)}},O.prototype={getValue:function(){var e=G(this.cache,this.propertyName);return void 0!==e?e:this.initialValue},setValue:function(e,t){e!==G(this.cache,this.propertyName)&&(t&&I(this.context,this.propertyName),void 0===e?Q(this.cache,this.propertyName):W(this.cache,this.propertyName,e),t&&k(this.context,this.propertyName))}},f.ReduceComputedProperty=E,E.prototype=q(H.prototype),E.prototype._callbacks=function(){if(!this.callbacks){var e=this.options;this.callbacks={removedItem:e.removedItem||P,addedItem:e.addedItem||P,flushedChanges:e.flushedChanges||P}}return this.callbacks},E.prototype._hasInstanceMeta=function(e,t){return!!S(e).cacheMeta[t]},E.prototype._instanceMeta=function(e,t){var r=S(e).cacheMeta,n=r[t];return n||(n=r[t]=new O(e,t,this.initialValue()),n.dependentArraysObserver=new v(this._callbacks(),this,n,e,t,n.sugarMeta)),n},E.prototype.initialValue=function(){return"function"==typeof this.options.initialValue?this.options.initialValue():this.options.initialValue},E.prototype.resetValue=function(){return this.initialValue()},E.prototype.itemPropertyKey=function(e,t){this._itemPropertyKeys[e]=this._itemPropertyKeys[e]||[],this._itemPropertyKeys[e].push(t)},E.prototype.clearItemPropertyKeys=function(e){this._itemPropertyKeys[e]&&(this._previousItemPropertyKeys[e]=this._itemPropertyKeys[e],this._itemPropertyKeys[e]=[])},E.prototype.property=function(){var e,t,r=this,n=$.call(arguments),i={};F(n,function(n){if(J.test(n))throw new V("Nested @each properties not supported: "+n);if(e=Y.exec(n)){t=e[1];var a=e[2],s=function(e){r.itemPropertyKey(t,e)};D(a,s),i[N(t)]=t}else i[N(n)]=n});var a=[];for(var s in i)a.push(i[s]);return H.prototype.property.apply(this,a)},f.reduceComputed=A}),e("ember-runtime/computed/reduce_computed_macros",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/error","ember-metal/enumerable_utils","ember-metal/run_loop","ember-metal/observer","ember-runtime/computed/array_computed","ember-runtime/computed/reduce_computed","ember-runtime/system/subarray","ember-metal/keys","ember-runtime/compare","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m){"use strict";function f(e){return M(e,{initialValue:0,addedItem:function(e,t){return e+t},removedItem:function(e,t){return e-t}})}function d(e){return M(e,{initialValue:-1/0,addedItem:function(e,t){return Math.max(e,t)},removedItem:function(e,t){return e>t?e:void 0}})}function v(e){return M(e,{initialValue:1/0,addedItem:function(e,t){return Math.min(e,t)},removedItem:function(e,t){return t>e?e:void 0}})}function b(e,t){var r={addedItem:function(e,r,n){var i=t.call(this,r,n.index);return e.insertAt(n.index,i),e},removedItem:function(e,t,r){return e.removeAt(r.index,1),e}};return j(e,r)}function y(e,t){var r=function(e){return N(e,t)};return b(e+".@each."+t,r)}function g(e,t){var r={initialize:function(e,t,r){r.filteredArrayIndexes=new R},addedItem:function(e,r,n,i){var a=!!t.call(this,r,n.index),s=i.filteredArrayIndexes.addItem(n.index,a);return a&&e.insertAt(s,r),e},removedItem:function(e,t,r,n){var i=n.filteredArrayIndexes.removeItem(r.index);return i>-1&&e.removeAt(i),e}};return j(e,r)}function _(e,t,r){var n;return n=2===arguments.length?function(e){return N(e,t)}:function(e){return N(e,t)===r},g(e+".@each."+t,n)}function w(){var e=z.call(arguments);return e.push({initialize:function(e,t,r){r.itemCounts={}},addedItem:function(e,t,r,n){var i=S(t);return n.itemCounts[i]?++n.itemCounts[i]:(n.itemCounts[i]=1,e.pushObject(t)),e},removedItem:function(e,t,r,n){var i=S(t),a=n.itemCounts;return 0===--a[i]&&e.removeObject(t),e}}),j.apply(null,e)}function x(){var e=z.call(arguments);return e.push({initialize:function(e,t,r){r.itemCounts={}},addedItem:function(e,t,r,n){var i=S(t),a=S(r.arrayChanged),s=r.property._dependentKeys.length,o=n.itemCounts;return o[i]||(o[i]={}),void 0===o[i][a]&&(o[i][a]=0),1===++o[i][a]&&s===L(o[i]).length&&e.addObject(t),e},removedItem:function(e,t,r,n){var i,a=S(t),s=S(r.arrayChanged),o=(r.property._dependentKeys.length,n.itemCounts);return void 0===o[a][s]&&(o[a][s]=0),0===--o[a][s]&&(delete o[a][s],i=L(o[a]).length,0===i&&delete o[a],e.removeObject(t)),e}}),j.apply(null,e)}function C(e,t){if(2!==arguments.length)throw new V("setDiff requires exactly two dependent arrays.");return j(e,t,{addedItem:function(r,n,i){var a=N(this,e),s=N(this,t);return i.arrayChanged===a?s.contains(n)||r.addObject(n):r.removeObject(n),r},removedItem:function(r,n,i){var a=N(this,e),s=N(this,t);return i.arrayChanged===s?a.contains(n)&&r.addObject(n):r.removeObject(n),r}})}function O(e,t,r,n){var i,a,s,o,u;return arguments.length<4&&(n=N(e,"length")),arguments.length<3&&(r=0),r===n?r:(i=r+Math.floor((n-r)/2),a=e.objectAt(i),o=S(a),u=S(t),o===u?i:(s=this.order(a,t),0===s&&(s=u>o?-1:1),0>s?this.binarySearch(e,t,i+1,n):s>0?this.binarySearch(e,t,r,i):i))}function E(e,t){return"function"==typeof t?P(e,t):A(e,t)}function P(e,t){return j(e,{initialize:function(e,r,n){n.order=t,n.binarySearch=O,n.waitingInsertions=[],n.insertWaiting=function(){var t,r,i=n.waitingInsertions;n.waitingInsertions=[];for(var a=0;a=0&&r>e&&(t=this.lookupItemController(i))?this.controllerAt(e,i,t):i},arrangedContentDidChange:function(){this._super(),this._resetSubControllers()},arrayContentDidChange:function(e,t,r){var n=this._subControllers;if(n.length){var i=n.slice(e,e+t);p(i,function(e){e&&e.destroy()}),m(n,e,t,new Array(r))}this._super(e,t,r)},init:function(){this._super(),this._subControllers=[]},model:b(function(){return c.A()}),_isVirtual:!1,controllerAt:function(e,t,r){var n,i,a,s=h(this,"container"),o=this._subControllers;if(o.length>e&&(i=o[e]))return i;if(a=this._isVirtual?h(this,"parentController"):this,n="controller:"+r,!s.has(n))throw new y('Could not resolve itemController: "'+r+'"');return i=s.lookupFactory(n).create({target:a,parentController:a,model:t}),o[e]=i,i},_subControllers:null,_resetSubControllers:function(){var e,t=this._subControllers;if(t.length){for(var r=0,n=t.length;n>r;r++)e=t[r],e&&e.destroy();t.length=0}},willDestroy:function(){this._resetSubControllers(),this._super()}})}),e("ember-runtime/controllers/controller",["ember-runtime/system/object","ember-runtime/mixins/controller","exports"],function(e,t,r){"use strict";var n=e["default"],i=t["default"];r["default"]=n.extend(i)}),e("ember-runtime/controllers/object_controller",["ember-runtime/mixins/controller","ember-runtime/system/object_proxy","exports"],function(e,t,r){"use strict";var n=e["default"],i=t["default"];r["default"]=i.extend(n)}),e("ember-runtime/copy",["ember-metal/enumerable_utils","ember-metal/utils","ember-runtime/system/object","ember-runtime/mixins/copyable","exports"],function(e,t,r,n,i){"use strict";function a(e,t,r,n){var i,l,c;if("object"!=typeof e||null===e)return e;if(t&&(l=s(r,e))>=0)return n[l];if("array"===o(e)){if(i=e.slice(),t)for(l=i.length;--l>=0;)i[l]=a(i[l],t,r,n)}else if(u&&u.detect(e))i=e.copy(t,r,n);else if(e instanceof Date)i=new Date(e.getTime());else{i={};for(c in e)Object.prototype.hasOwnProperty.call(e,c)&&"__"!==c.substring(0,2)&&(i[c]=t?a(e[c],t,r,n):e[c])}return t&&(r.push(e),n.push(i)),i}var s=e.indexOf,o=t.typeOf,u=(r["default"],n["default"]);i["default"]=function(e,t){return"object"!=typeof e||null===e?e:u&&u.detect(e)?e.copy(t):a(e,t,t?[]:null,t?[]:null)}}),e("ember-runtime/core",["exports"],function(e){"use strict";var t=function(e,t){return e&&"function"==typeof e.isEqual?e.isEqual(t):e instanceof Date&&t instanceof Date?e.getTime()===t.getTime():e===t};e.isEqual=t}),e("ember-runtime/ext/function",["ember-metal/core","ember-metal/expand_properties","ember-metal/computed","ember-metal/mixin"],function(e,t,r,n){"use strict";var i=e["default"],a=t["default"],s=r.computed,o=n.observer,u=Array.prototype.slice,l=Function.prototype;(i.EXTEND_PROTOTYPES===!0||i.EXTEND_PROTOTYPES.Function)&&(l.property=function(){var e=s(this);return e.property.apply(e,arguments)},l.observes=function(){for(var e=arguments.length,t=new Array(e),r=0;e>r;r++)t[r]=arguments[r];return o.apply(this,t.concat(this))},l.observesImmediately=function(){for(var e=0,t=arguments.length;t>e;e++){arguments[e]}return this.observes.apply(this,arguments)},l.observesBefore=function(){for(var e=[],t=function(t){e.push(t)},r=0,n=arguments.length;n>r;++r)a(arguments[r],t);return this.__ember_observesBefore__=e,this},l.on=function(){var e=u.call(arguments);return this.__ember_listens__=e,this})}),e("ember-runtime/ext/rsvp",["ember-metal/core","ember-metal/logger","ember-metal/run_loop","exports"],function(e,r,n,i){"use strict";var a,s=e["default"],o=r["default"],u=n["default"],l=t("rsvp"),c="ember-testing/test",h=function(){s.Test&&s.Test.adapter&&s.Test.adapter.asyncStart()},p=function(){s.Test&&s.Test.adapter&&s.Test.adapter.asyncEnd()};l.configure("async",function(e,t){var r=!u.currentRunLoop;s.testing&&r&&h(),u.backburner.schedule("actions",function(){s.testing&&r&&p(),e(t)})}),l.Promise.prototype.fail=function(e,t){return this["catch"](e,t)},l.onerrorDefault=function(e){if(e instanceof Error)if(s.testing){if(!a&&s.__loader.registry[c]&&(a=t(c)["default"]),!a||!a.adapter)throw e;a.adapter.exception(e)}else s.onerror?s.onerror(e):o.error(e.stack)},l.on("error",l.onerrorDefault),i["default"]=l}),e("ember-runtime/ext/string",["ember-metal/core","ember-runtime/system/string"],function(e,t){"use strict";var r=e["default"],n=t.fmt,i=t.w,a=t.loc,s=t.camelize,o=t.decamelize,u=t.dasherize,l=t.underscore,c=t.capitalize,h=t.classify,p=String.prototype;(r.EXTEND_PROTOTYPES===!0||r.EXTEND_PROTOTYPES.String)&&(p.fmt=function(){return n(this,arguments)},p.w=function(){return i(this)},p.loc=function(){return a(this,arguments)},p.camelize=function(){return s(this)},p.decamelize=function(){return o(this)},p.dasherize=function(){return u(this)},p.underscore=function(){return l(this)},p.classify=function(){return h(this)},p.capitalize=function(){return c(this)})}),e("ember-runtime/mixins/-proxy",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/observer","ember-metal/property_events","ember-metal/computed","ember-metal/properties","ember-metal/mixin","ember-runtime/system/string","ember-runtime/system/object","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h){"use strict";function p(e,t){var r=t.slice(8);r in this||w(this,r)}function m(e,t){var r=t.slice(8);r in this||x(this,r)}{var f=(e["default"],t.get),d=r.set,v=n.meta,b=i.addObserver,y=i.removeObserver,g=i.addBeforeObserver,_=i.removeBeforeObserver,w=a.propertyWillChange,x=a.propertyDidChange,C=s.computed,O=o.defineProperty,E=u.Mixin,P=u.observer;l.fmt,c["default"]}h["default"]=E.create({content:null,_contentDidChange:P("content",function(){}),isTruthy:C.bool("content"),_debugContainerKey:null,willWatchProperty:function(e){var t="content."+e;g(this,t,null,p),b(this,t,null,m)},didUnwatchProperty:function(e){var t="content."+e;_(this,t,null,p),y(this,t,null,m)},unknownProperty:function(e){var t=f(this,"content");return t?f(t,e):void 0},setUnknownProperty:function(e,t){var r=v(this);if(r.proto===this)return O(this,e,null,t),t;var n=f(this,"content");return d(n,e,t)}})}),e("ember-runtime/mixins/action_handler",["ember-metal/merge","ember-metal/mixin","ember-metal/property_get","ember-metal/utils","exports"],function(e,t,r,n,i){"use strict";var a=e["default"],s=t.Mixin,o=r.get,u=n.typeOf,l=s.create({mergedProperties:["_actions"],willMergeMixin:function(e){var t;e._actions||("object"===u(e.actions)?t="actions":"object"===u(e.events)&&(t="events"),t&&(e._actions=a(e._actions||{},e[t])),delete e[t])},send:function(e){var t,r=[].slice.call(arguments,1);this._actions&&this._actions[e]&&this._actions[e].apply(this,r)!==!0||(t=o(this,"target"))&&t.send.apply(t,arguments)}});i["default"]=l}),e("ember-runtime/mixins/array",["ember-metal/core","ember-metal/property_get","ember-metal/computed","ember-metal/is_none","ember-runtime/mixins/enumerable","ember-metal/enumerable_utils","ember-metal/mixin","ember-metal/property_events","ember-metal/events","ember-metal/watching","exports"],function(e,r,n,i,a,s,o,u,l,c,h){"use strict";function p(e,t,r,n,i){var a=r&&r.willChange||"arrayWillChange",s=r&&r.didChange||"arrayDidChange",o=f(e,"hasArrayObservers");return o===i&&x(e,"hasArrayObservers"),n(e,"@array:before",t,a),n(e,"@array:change",t,s),o===i&&C(e,"hasArrayObservers"),e}var m=e["default"],f=r.get,d=n.computed,v=n.cacheFor,b=i.isNone,y=(i.none,a["default"]),g=s.map,_=o.Mixin,w=o.required,x=u.propertyWillChange,C=u.propertyDidChange,O=l.addListener,E=l.removeListener,P=l.sendEvent,A=l.hasListeners,T=c.isWatching;h["default"]=_.create(y,{length:w(),objectAt:function(e){return 0>e||e>=f(this,"length")?void 0:f(this,e)},objectsAt:function(e){var t=this;return g(e,function(e){return t.objectAt(e)})},nextObject:function(e){return this.objectAt(e)},"[]":d(function(e,t){return void 0!==t&&this.replace(0,f(this,"length"),t),this}),firstObject:d(function(){return this.objectAt(0)}),lastObject:d(function(){return this.objectAt(f(this,"length")-1)}),contains:function(e){return this.indexOf(e)>=0},slice:function(e,t){var r=m.A(),n=f(this,"length");for(b(e)&&(e=0),(b(t)||t>n)&&(t=n),0>e&&(e=n+e),0>t&&(t=n+t);t>e;)r[r.length]=this.objectAt(e++);return r},indexOf:function(e,t){var r,n=f(this,"length");for(void 0===t&&(t=0),0>t&&(t+=n),r=t;n>r;r++)if(this.objectAt(r)===e)return r;return-1},lastIndexOf:function(e,t){var r,n=f(this,"length");for((void 0===t||t>=n)&&(t=n-1),0>t&&(t+=n),r=t;r>=0;r--)if(this.objectAt(r)===e)return r;return-1},addArrayObserver:function(e,t){return p(this,e,t,O,!1)},removeArrayObserver:function(e,t){return p(this,e,t,E,!0)},hasArrayObservers:d(function(){return A(this,"@array:change")||A(this,"@array:before")}),arrayContentWillChange:function(e,t,r){var n,i;if(void 0===e?(e=0,t=r=-1):(void 0===t&&(t=-1),void 0===r&&(r=-1)),T(this,"@each")&&f(this,"@each"),P(this,"@array:before",[this,e,t,r]),e>=0&&t>=0&&f(this,"hasEnumerableObservers")){n=[],i=e+t;for(var a=e;i>a;a++)n.push(this.objectAt(a))}else n=t;return this.enumerableContentWillChange(n,r),this},arrayContentDidChange:function(e,t,r){var n,i;if(void 0===e?(e=0,t=r=-1):(void 0===t&&(t=-1),void 0===r&&(r=-1)),e>=0&&r>=0&&f(this,"hasEnumerableObservers")){n=[],i=e+r;for(var a=e;i>a;a++)n.push(this.objectAt(a))}else n=r;this.enumerableContentDidChange(t,n),P(this,"@array:change",[this,e,t,r]);var s=f(this,"length"),o=v(this,"firstObject"),u=v(this,"lastObject");return this.objectAt(0)!==o&&(x(this,"firstObject"),C(this,"firstObject")),this.objectAt(s-1)!==u&&(x(this,"lastObject"),C(this,"lastObject")),this},"@each":d(function(){if(!this.__each){var e=t("ember-runtime/system/each_proxy").EachProxy;this.__each=new e(this)}return this.__each})})}),e("ember-runtime/mixins/comparable",["ember-metal/mixin","exports"],function(e,t){"use strict";var r=e.Mixin,n=e.required;t["default"]=r.create({compare:n(Function)})}),e("ember-runtime/mixins/controller",["ember-metal/core","ember-metal/property_get","ember-runtime/system/object","ember-metal/mixin","ember-metal/computed","ember-runtime/mixins/action_handler","ember-runtime/mixins/controller_content_model_alias_deprecation","exports"],function(e,t,r,n,i,a,s,o){"use strict";var u=(e["default"],t.get,r["default"],n.Mixin),l=i.computed,c=a["default"],h=s["default"];o["default"]=u.create(c,h,{isController:!0,target:null,container:null,parentController:null,store:null,model:null,content:l.alias("model")})}),e("ember-runtime/mixins/controller_content_model_alias_deprecation",["ember-metal/core","ember-metal/property_get","ember-metal/mixin","exports"],function(e,t,r,n){"use strict";var i=(e["default"],t.get,r.Mixin);n["default"]=i.create({willMergeMixin:function(e){this._super.apply(this,arguments);var t=!!e.model;e.content&&!t&&(e.model=e.content,delete e.content)}})}),e("ember-runtime/mixins/copyable",["ember-metal/property_get","ember-metal/property_set","ember-metal/mixin","ember-runtime/mixins/freezable","ember-runtime/system/string","ember-metal/error","exports"],function(e,t,r,n,i,a,s){"use strict";var o=e.get,u=(t.set,r.required),l=n.Freezable,c=r.Mixin,h=i.fmt,p=a["default"];s["default"]=c.create({copy:u(Function),frozenCopy:function(){if(l&&l.detect(this))return o(this,"isFrozen")?this:this.copy().freeze();throw new p(h("%@ does not support freezing",[this]))}})}),e("ember-runtime/mixins/deferred",["ember-metal/core","ember-metal/property_get","ember-metal/mixin","ember-metal/computed","ember-runtime/ext/rsvp","exports"],function(e,t,r,n,i,a){"use strict";var s=(e["default"],t.get),o=r.Mixin,u=n.computed,l=i["default"];a["default"]=o.create({then:function(e,t,r){function n(t){return e(t===a?o:t)}var i,a,o;return o=this,i=s(this,"_deferred"),a=i.promise,a.then(e&&n,t,r)},resolve:function(e){var t,r;t=s(this,"_deferred"),r=t.promise,t.resolve(e===this?r:e)},reject:function(e){s(this,"_deferred").reject(e)},_deferred:u(function(){return l.defer("Ember: DeferredMixin - "+this)})})}),e("ember-runtime/mixins/enumerable",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/mixin","ember-metal/enumerable_utils","ember-metal/computed","ember-metal/property_events","ember-metal/events","ember-runtime/compare","exports"],function(e,t,r,n,i,a,s,o,u,l,c){"use strict";function h(){return 0===V.length?{}:V.pop()}function p(e){return V.push(e),null}function m(e,t){function r(r){var i=d(r,e);return n?t===i:!!i}var n=2===arguments.length;return r}var f=e["default"],d=t.get,v=r.set,b=n.apply,y=i.Mixin,g=i.required,_=i.aliasMethod,w=a.indexOf,x=s.computed,C=o.propertyWillChange,O=o.propertyDidChange,E=u.addListener,P=u.removeListener,A=u.sendEvent,T=u.hasListeners,N=l["default"],S=Array.prototype.slice,V=[];c["default"]=y.create({nextObject:g(Function),firstObject:x("[]",function(){if(0===d(this,"length"))return void 0;var e,t=h();return e=this.nextObject(0,null,t),p(t),e}),lastObject:x("[]",function(){var e=d(this,"length");if(0===e)return void 0;var t,r=h(),n=0,i=null;do i=t,t=this.nextObject(n++,i,r);while(void 0!==t);return p(r),i}),contains:function(e){return void 0!==this.find(function(t){return t===e})},forEach:function(e,t){if("function"!=typeof e)throw new TypeError;var r=d(this,"length"),n=null,i=h();void 0===t&&(t=null);for(var a=0;r>a;a++){var s=this.nextObject(a,n,i);e.call(t,s,a,this),n=s}return n=null,i=p(i),this},getEach:function(e){return this.mapBy(e)},setEach:function(e,t){return this.forEach(function(r){v(r,e,t)})},map:function(e,t){var r=f.A();return this.forEach(function(n,i,a){r[i]=e.call(t,n,i,a)}),r},mapBy:function(e){return this.map(function(t){return d(t,e)})},mapProperty:_("mapBy"),filter:function(e,t){var r=f.A();return this.forEach(function(n,i,a){e.call(t,n,i,a)&&r.push(n)}),r},reject:function(e,t){return this.filter(function(){return!b(t,e,arguments)})},filterBy:function(){return this.filter(b(this,m,arguments))},filterProperty:_("filterBy"),rejectBy:function(e,t){var r=function(r){return d(r,e)===t},n=function(t){return!!d(t,e)},i=2===arguments.length?r:n;return this.reject(i)},rejectProperty:_("rejectBy"),find:function(e,t){var r=d(this,"length");void 0===t&&(t=null);for(var n,i,a=null,s=!1,o=h(),u=0;r>u&&!s;u++)n=this.nextObject(u,a,o),(s=e.call(t,n,u,this))&&(i=n),a=n;return n=a=null,o=p(o),i},findBy:function(){return this.find(b(this,m,arguments))},findProperty:_("findBy"),every:function(e,t){return!this.find(function(r,n,i){return!e.call(t,r,n,i)})},everyBy:_("isEvery"),everyProperty:_("isEvery"),isEvery:function(){return this.every(b(this,m,arguments))},any:function(e,t){var r,n,i=d(this,"length"),a=h(),s=!1,o=null;for(void 0===t&&(t=null),n=0;i>n&&!s;n++)r=this.nextObject(n,o,a),s=e.call(t,r,n,this),o=r;return r=o=null,a=p(a),s},some:_("any"),isAny:function(){return this.any(b(this,m,arguments))},anyBy:_("isAny"),someProperty:_("isAny"),reduce:function(e,t,r){if("function"!=typeof e)throw new TypeError;var n=t;return this.forEach(function(t,i){n=e(n,t,i,this,r)},this),n},invoke:function(e){var t,r=f.A();return arguments.length>1&&(t=S.call(arguments,1)),this.forEach(function(n,i){var a=n&&n[e];"function"==typeof a&&(r[i]=t?b(n,a,t):n[e]())},this),r},toArray:function(){var e=f.A();return this.forEach(function(t,r){e[r]=t}),e},compact:function(){return this.filter(function(e){return null!=e})},without:function(e){if(!this.contains(e))return this;var t=f.A();return this.forEach(function(r){r!==e&&(t[t.length]=r)}),t},uniq:function(){var e=f.A();return this.forEach(function(t){w(e,t)<0&&e.push(t)}),e},"[]":x(function(){return this}),addEnumerableObserver:function(e,t){var r=t&&t.willChange||"enumerableWillChange",n=t&&t.didChange||"enumerableDidChange",i=d(this,"hasEnumerableObservers");return i||C(this,"hasEnumerableObservers"),E(this,"@enumerable:before",e,r),E(this,"@enumerable:change",e,n),i||O(this,"hasEnumerableObservers"),this},removeEnumerableObserver:function(e,t){var r=t&&t.willChange||"enumerableWillChange",n=t&&t.didChange||"enumerableDidChange",i=d(this,"hasEnumerableObservers"); +return i&&C(this,"hasEnumerableObservers"),P(this,"@enumerable:before",e,r),P(this,"@enumerable:change",e,n),i&&O(this,"hasEnumerableObservers"),this},hasEnumerableObservers:x(function(){return T(this,"@enumerable:change")||T(this,"@enumerable:before")}),enumerableContentWillChange:function(e,t){var r,n,i;return r="number"==typeof e?e:e?d(e,"length"):e=-1,n="number"==typeof t?t:t?d(t,"length"):t=-1,i=0>n||0>r||n-r!==0,-1===e&&(e=null),-1===t&&(t=null),C(this,"[]"),i&&C(this,"length"),A(this,"@enumerable:before",[this,e,t]),this},enumerableContentDidChange:function(e,t){var r,n,i;return r="number"==typeof e?e:e?d(e,"length"):e=-1,n="number"==typeof t?t:t?d(t,"length"):t=-1,i=0>n||0>r||n-r!==0,-1===e&&(e=null),-1===t&&(t=null),A(this,"@enumerable:change",[this,e,t]),i&&O(this,"length"),O(this,"[]"),this},sortBy:function(){var e=arguments;return this.toArray().sort(function(t,r){for(var n=0;nn;n++)r[n-1]=arguments[n];o(this,e,r)},off:function(e,t,r){return a(this,e,t,r),this},has:function(e){return s(this,e)}})}),e("ember-runtime/mixins/freezable",["ember-metal/mixin","ember-metal/property_get","ember-metal/property_set","exports"],function(e,t,r,n){"use strict";var i=e.Mixin,a=t.get,s=r.set,o=i.create({isFrozen:!1,freeze:function(){return a(this,"isFrozen")?this:(s(this,"isFrozen",!0),this)}});n.Freezable=o;var u="Frozen object cannot be modified.";n.FROZEN_ERROR=u}),e("ember-runtime/mixins/mutable_array",["ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/error","ember-metal/mixin","ember-runtime/mixins/array","ember-runtime/mixins/mutable_enumerable","ember-runtime/mixins/enumerable","exports"],function(e,t,r,n,i,a,s,o,u){"use strict";var l="Index out of range",c=[],h=e.get,p=(t.set,r.isArray),m=n["default"],f=i.Mixin,d=i.required,v=a["default"],b=s["default"],y=o["default"];u["default"]=f.create(v,b,{replace:d(),clear:function(){var e=h(this,"length");return 0===e?this:(this.replace(0,e,c),this)},insertAt:function(e,t){if(e>h(this,"length"))throw new m(l);return this.replace(e,0,[t]),this},removeAt:function(e,t){if("number"==typeof e){if(0>e||e>=h(this,"length"))throw new m(l);void 0===t&&(t=1),this.replace(e,t,c)}return this},pushObject:function(e){return this.insertAt(h(this,"length"),e),e},pushObjects:function(e){if(!y.detect(e)&&!p(e))throw new TypeError("Must pass Ember.Enumerable to Ember.MutableArray#pushObjects");return this.replace(h(this,"length"),0,e),this},popObject:function(){var e=h(this,"length");if(0===e)return null;var t=this.objectAt(e-1);return this.removeAt(e-1,1),t},shiftObject:function(){if(0===h(this,"length"))return null;var e=this.objectAt(0);return this.removeAt(0),e},unshiftObject:function(e){return this.insertAt(0,e),e},unshiftObjects:function(e){return this.replace(0,0,e),this},reverseObjects:function(){var e=h(this,"length");if(0===e)return this;var t=this.toArray().reverse();return this.replace(0,e,t),this},setObjects:function(e){if(0===e.length)return this.clear();var t=h(this,"length");return this.replace(0,t,e),this},removeObject:function(e){for(var t=h(this,"length")||0;--t>=0;){var r=this.objectAt(t);r===e&&this.removeAt(t)}return this},addObject:function(e){return this.contains(e)||this.pushObject(e),this}})}),e("ember-runtime/mixins/mutable_enumerable",["ember-metal/enumerable_utils","ember-runtime/mixins/enumerable","ember-metal/mixin","ember-metal/property_events","exports"],function(e,t,r,n,i){"use strict";var a=e.forEach,s=t["default"],o=r.Mixin,u=r.required,l=n.beginPropertyChanges,c=n.endPropertyChanges;i["default"]=o.create(s,{addObject:u(Function),addObjects:function(e){return l(this),a(e,function(e){this.addObject(e)},this),c(this),this},removeObject:u(Function),removeObjects:function(e){l(this);for(var t=e.length-1;t>=0;t--)this.removeObject(e[t]);return c(this),this}})}),e("ember-runtime/mixins/observable",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/get_properties","ember-metal/set_properties","ember-metal/mixin","ember-metal/events","ember-metal/property_events","ember-metal/observer","ember-metal/computed","ember-metal/is_none","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p){"use strict";var m=(e["default"],t.get),f=t.getWithDefault,d=r.set,v=n.apply,b=i["default"],y=a["default"],g=s.Mixin,_=o.hasListeners,w=u.beginPropertyChanges,x=u.propertyWillChange,C=u.propertyDidChange,O=u.endPropertyChanges,E=l.addObserver,P=l.addBeforeObserver,A=l.removeObserver,T=l.observersFor,N=c.cacheFor,S=h.isNone,V=Array.prototype.slice;p["default"]=g.create({get:function(e){return m(this,e)},getProperties:function(){return v(null,b,[this].concat(V.call(arguments)))},set:function(e,t){return d(this,e,t),this},setProperties:function(e){return y(this,e)},beginPropertyChanges:function(){return w(),this},endPropertyChanges:function(){return O(),this},propertyWillChange:function(e){return x(this,e),this},propertyDidChange:function(e){return C(this,e),this},notifyPropertyChange:function(e){return this.propertyWillChange(e),this.propertyDidChange(e),this},addBeforeObserver:function(e,t,r){P(this,e,t,r)},addObserver:function(e,t,r){E(this,e,t,r)},removeObserver:function(e,t,r){A(this,e,t,r)},hasObserverFor:function(e){return _(this,e+":change")},getWithDefault:function(e,t){return f(this,e,t)},incrementProperty:function(e,t){return S(t)&&(t=1),d(this,e,(parseFloat(m(this,e))||0)+t),m(this,e)},decrementProperty:function(e,t){return S(t)&&(t=1),d(this,e,(m(this,e)||0)-t),m(this,e)},toggleProperty:function(e){return d(this,e,!m(this,e)),m(this,e)},cacheFor:function(e){return N(this,e)},observersForKey:function(e){return T(this,e)}})}),e("ember-runtime/mixins/promise_proxy",["ember-metal/property_get","ember-metal/set_properties","ember-metal/computed","ember-metal/mixin","ember-metal/error","exports"],function(e,t,r,n,i,a){"use strict";function s(e,t){return l(e,{isFulfilled:!1,isRejected:!1}),t.then(function(t){return l(e,{content:t,isFulfilled:!0}),t},function(t){throw l(e,{reason:t,isRejected:!0}),t},"Ember: PromiseProxy")}function o(e){return function(){var t=u(this,"promise");return t[e].apply(t,arguments)}}var u=e.get,l=t["default"],c=r.computed,h=n.Mixin,p=i["default"],m=c.not,f=c.or;a["default"]=h.create({reason:null,isPending:m("isSettled").readOnly(),isSettled:f("isRejected","isFulfilled").readOnly(),isRejected:!1,isFulfilled:!1,promise:c(function(e,t){if(2===arguments.length)return s(this,t);throw new p("PromiseProxy's promise must be set")}),then:o("then"),"catch":o("catch"),"finally":o("finally")})}),e("ember-runtime/mixins/sortable",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/enumerable_utils","ember-metal/mixin","ember-runtime/mixins/mutable_enumerable","ember-runtime/compare","ember-metal/observer","ember-metal/computed","exports"],function(e,t,r,n,i,a,s,o,u,l){"use strict";var c=e["default"],h=t.get,p=(r.set,n.forEach),m=i.Mixin,f=a["default"],d=s["default"],v=o.addObserver,b=o.removeObserver,y=u.computed,g=i.beforeObserver,_=i.observer;l["default"]=m.create(f,{sortProperties:null,sortAscending:!0,sortFunction:d,orderBy:function(e,t){var r=0,n=h(this,"sortProperties"),i=h(this,"sortAscending"),a=h(this,"sortFunction");return p(n,function(n){0===r&&(r=a.call(this,h(e,n),h(t,n)),0===r||i||(r=-1*r))},this),r},destroy:function(){var e=h(this,"content"),t=h(this,"sortProperties");return e&&t&&p(e,function(e){p(t,function(t){b(e,t,this,"contentItemSortPropertyDidChange")},this)},this),this._super()},isSorted:y.notEmpty("sortProperties"),arrangedContent:y("content","sortProperties.@each",function(){var e=h(this,"content"),t=h(this,"isSorted"),r=h(this,"sortProperties"),n=this;return e&&t?(e=e.slice(),e.sort(function(e,t){return n.orderBy(e,t)}),p(e,function(e){p(r,function(t){v(e,t,this,"contentItemSortPropertyDidChange")},this)},this),c.A(e)):e}),_contentWillChange:g("content",function(){var e=h(this,"content"),t=h(this,"sortProperties");e&&t&&p(e,function(e){p(t,function(t){b(e,t,this,"contentItemSortPropertyDidChange")},this)},this),this._super()}),sortPropertiesWillChange:g("sortProperties",function(){this._lastSortAscending=void 0}),sortPropertiesDidChange:_("sortProperties",function(){this._lastSortAscending=void 0}),sortAscendingWillChange:g("sortAscending",function(){this._lastSortAscending=h(this,"sortAscending")}),sortAscendingDidChange:_("sortAscending",function(){if(void 0!==this._lastSortAscending&&h(this,"sortAscending")!==this._lastSortAscending){var e=h(this,"arrangedContent");e.reverseObjects()}}),contentArrayWillChange:function(e,t,r,n){var i=h(this,"isSorted");if(i){var a=h(this,"arrangedContent"),s=e.slice(t,t+r),o=h(this,"sortProperties");p(s,function(e){a.removeObject(e),p(o,function(t){b(e,t,this,"contentItemSortPropertyDidChange")},this)},this)}return this._super(e,t,r,n)},contentArrayDidChange:function(e,t,r,n){var i=h(this,"isSorted"),a=h(this,"sortProperties");if(i){var s=e.slice(t,t+n);p(s,function(e){this.insertItemSorted(e),p(a,function(t){v(e,t,this,"contentItemSortPropertyDidChange")},this)},this)}return this._super(e,t,r,n)},insertItemSorted:function(e){var t=h(this,"arrangedContent"),r=h(t,"length"),n=this._binarySearch(e,0,r);t.insertAt(n,e)},contentItemSortPropertyDidChange:function(e){var t=h(this,"arrangedContent"),r=t.indexOf(e),n=t.objectAt(r-1),i=t.objectAt(r+1),a=n&&this.orderBy(e,n),s=i&&this.orderBy(e,i);(0>a||s>0)&&(t.removeObject(e),this.insertItemSorted(e))},_binarySearch:function(e,t,r){var n,i,a,s;return t===r?t:(s=h(this,"arrangedContent"),n=t+Math.floor((r-t)/2),i=s.objectAt(n),a=this.orderBy(i,e),0>a?this._binarySearch(e,n+1,r):a>0?this._binarySearch(e,t,n):n)}})}),e("ember-runtime/mixins/target_action_support",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/mixin","ember-metal/computed","exports"],function(e,t,r,n,i,a,s){"use strict";var o=e["default"],u=t.get,l=(r.set,n.typeOf),c=i.Mixin,h=a.computed,p=c.create({target:null,action:null,actionContext:null,targetObject:h(function(){var e=u(this,"target");if("string"===l(e)){var t=u(this,e);return void 0===t&&(t=u(o.lookup,e)),t}return e}).property("target"),actionContextObject:h(function(){var e=u(this,"actionContext");if("string"===l(e)){var t=u(this,e);return void 0===t&&(t=u(o.lookup,e)),t}return e}).property("actionContext"),triggerAction:function(e){function t(e,t){var r=[];return t&&r.push(t),r.concat(e)}e=e||{};var r=e.action||u(this,"action"),n=e.target||u(this,"targetObject"),i=e.actionContext;if("undefined"==typeof i&&(i=u(this,"actionContextObject")||this),n&&r){var a;return a=n.send?n.send.apply(n,t(i,r)):n[r].apply(n,t(i)),a!==!1&&(a=!0),a}return!1}});s["default"]=p}),e("ember-runtime/system/application",["ember-runtime/system/namespace","exports"],function(e,t){"use strict";var r=e["default"];t["default"]=r.extend()}),e("ember-runtime/system/array_proxy",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/computed","ember-metal/mixin","ember-metal/property_events","ember-metal/error","ember-runtime/system/object","ember-runtime/mixins/mutable_array","ember-runtime/mixins/enumerable","ember-runtime/system/string","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p){"use strict";var m=e["default"],f=t.get,d=(r.set,n.isArray),v=n.apply,b=i.computed,y=a.beforeObserver,g=a.observer,_=s.beginPropertyChanges,w=s.endPropertyChanges,x=o["default"],C=u["default"],O=l["default"],E=c["default"],P=(h.fmt,"Index out of range"),A=[],T=b.alias,N=m.K,S=C.extend(O,{content:null,arrangedContent:T("content"),objectAtContent:function(e){return f(this,"arrangedContent").objectAt(e)},replaceContent:function(e,t,r){f(this,"content").replace(e,t,r)},_contentWillChange:y("content",function(){this._teardownContent()}),_teardownContent:function(){var e=f(this,"content");e&&e.removeArrayObserver(this,{willChange:"contentArrayWillChange",didChange:"contentArrayDidChange"})},contentArrayWillChange:N,contentArrayDidChange:N,_contentDidChange:g("content",function(){f(this,"content");this._setupContent()}),_setupContent:function(){var e=f(this,"content");e&&e.addArrayObserver(this,{willChange:"contentArrayWillChange",didChange:"contentArrayDidChange"})},_arrangedContentWillChange:y("arrangedContent",function(){var e=f(this,"arrangedContent"),t=e?f(e,"length"):0;this.arrangedContentArrayWillChange(this,0,t,void 0),this.arrangedContentWillChange(this),this._teardownArrangedContent(e)}),_arrangedContentDidChange:g("arrangedContent",function(){var e=f(this,"arrangedContent"),t=e?f(e,"length"):0;this._setupArrangedContent(),this.arrangedContentDidChange(this),this.arrangedContentArrayDidChange(this,0,void 0,t)}),_setupArrangedContent:function(){var e=f(this,"arrangedContent");e&&e.addArrayObserver(this,{willChange:"arrangedContentArrayWillChange",didChange:"arrangedContentArrayDidChange"})},_teardownArrangedContent:function(){var e=f(this,"arrangedContent");e&&e.removeArrayObserver(this,{willChange:"arrangedContentArrayWillChange",didChange:"arrangedContentArrayDidChange"})},arrangedContentWillChange:N,arrangedContentDidChange:N,objectAt:function(e){return f(this,"content")&&this.objectAtContent(e)},length:b(function(){var e=f(this,"arrangedContent");return e?f(e,"length"):0}),_replace:function(e,t,r){var n=f(this,"content");return n&&this.replaceContent(e,t,r),this},replace:function(){if(f(this,"arrangedContent")!==f(this,"content"))throw new x("Using replace on an arranged ArrayProxy is not allowed.");v(this,this._replace,arguments)},_insertAt:function(e,t){if(e>f(this,"content.length"))throw new x(P);return this._replace(e,0,[t]),this},insertAt:function(e,t){if(f(this,"arrangedContent")===f(this,"content"))return this._insertAt(e,t);throw new x("Using insertAt on an arranged ArrayProxy is not allowed.")},removeAt:function(e,t){if("number"==typeof e){var r,n=f(this,"content"),i=f(this,"arrangedContent"),a=[];if(0>e||e>=f(this,"length"))throw new x(P);for(void 0===t&&(t=1),r=e;e+t>r;r++)a.push(n.indexOf(i.objectAt(r)));for(a.sort(function(e,t){return t-e}),_(),r=0;rl;l++){var h=o[l];if("object"!=typeof h&&void 0!==h)throw new M("Ember.Object.create only accepts objects.");if(h)for(var p=L(h),m=0,f=p.length;f>m;m++){var d=p[m];if(h.hasOwnProperty(d)){var v=h[d];if(I.test(d)){var b=i.bindings;b?i.hasOwnProperty("bindings")||(b=i.bindings=O(i.bindings)):b=i.bindings={},b[d]=v}var y=i.descs[d];if(u&&j(u,d)>=0){var g=this[d];v=g?"function"==typeof g.concat?g.concat(v):T(g).concat(v):T(v)}y?y.set(this,d,v):"function"!=typeof this.setUnknownProperty||d in this?this[d]=v:this.setUnknownProperty(d,v)}}}}W(this,i);for(var _=arguments.length,w=new Array(_),x=0;_>x;x++)w[x]=arguments[x];C(this,this.init,w),i.proto=a,S(this),V(this,"init")};return n.toString=k.prototype.toString,n.willReopen=function(){r&&(n.PrototypeMixin=k.create(n.PrototypeMixin)),r=!1},n._initMixins=function(t){e=t},n._initProperties=function(e){t=e},n.proto=function(){var e=n.superclass;return e&&e.proto(),r||(r=!0,n.PrototypeMixin.applyPartial(n.prototype),N(n.prototype)),this.prototype},n}function g(e){return function(){return e}}var _=e["default"],w=t.get,x=(r.set,n.guidFor),C=n.apply,O=i.create,E=n.generateGuid,P=n.GUID_KEY,A=n.meta,T=n.makeArray,N=a.rewatch,S=s.finishChains,V=o.sendEvent,I=u.IS_BINDING,k=u.Mixin,D=u.required,j=l.indexOf,M=c["default"],R=i.defineProperty,L=h["default"],H=(p["default"],m.defineProperty,f.Binding),z=d.ComputedProperty,q=v["default"],F=a.destroy,B=e.K,U=(i.hasPropertyAccessors,q.schedule),K=k._apply,W=k.finishPartial,G=k.prototype.reopen,Q=!1,$={configurable:!0,writable:!0,enumerable:!1,value:void 0},Y={configurable:!0,writable:!0,enumerable:!1,value:null},J=y();J.toString=function(){return"Ember.CoreObject"},J.PrototypeMixin=k.create({reopen:function(){for(var e=arguments.length,t=new Array(e),r=0;e>r;r++)t[r]=arguments[r];return K(this,t,!0),this},init:function(){},concatenatedProperties:null,isDestroyed:!1,isDestroying:!1,destroy:function(){return this.isDestroying?void 0:(this.isDestroying=!0,U("actions",this,this.willDestroy),U("destroy",this,this._scheduledDestroy),this)},willDestroy:B,_scheduledDestroy:function(){this.isDestroyed||(F(this),this.isDestroyed=!0)},bind:function(e,t){return t instanceof H||(t=H.from(t)),t.to(e).connect(this),t},toString:function(){var e="function"==typeof this.toStringExtension,t=e?":"+this.toStringExtension():"",r="<"+this.constructor.toString()+":"+x(this)+t+">";return this.toString=g(r),r}}),J.PrototypeMixin.ownerConstructor=J,_.config.overridePrototypeMixin&&_.config.overridePrototypeMixin(J.PrototypeMixin),J.__super__=null;var Z=k.create({ClassMixin:D(),PrototypeMixin:D(),isClass:!0,isMethod:!1,extend:function(){var e,t=y();return t.ClassMixin=k.create(this.ClassMixin),t.PrototypeMixin=k.create(this.PrototypeMixin),t.ClassMixin.ownerConstructor=t,t.PrototypeMixin.ownerConstructor=t,G.apply(t.PrototypeMixin,arguments),t.superclass=this,t.__super__=this.prototype,e=t.prototype=O(this.prototype),e.constructor=t,E(e),A(e).proto=e,t.ClassMixin.apply(t),t},createWithMixins:function(){var e=this,t=arguments.length;if(t>0){for(var r=new Array(t),n=0;t>n;n++)r[n]=arguments[n];this._initMixins(r)}return new e},create:function(){var e=this,t=arguments.length;if(t>0){for(var r=new Array(t),n=0;t>n;n++)r[n]=arguments[n];this._initProperties(r)}return new e},reopen:function(){this.willReopen();var e=arguments.length,t=new Array(e);if(e>0)for(var r=0;e>r;r++)t[r]=arguments[r];return C(this.PrototypeMixin,G,t),this},reopenClass:function(){var e=arguments.length,t=new Array(e);if(e>0)for(var r=0;e>r;r++)t[r]=arguments[r];return C(this.ClassMixin,G,t),K(this,arguments,!1),this},detect:function(e){if("function"!=typeof e)return!1;for(;e;){if(e===this)return!0;e=e.superclass}return!1},detectInstance:function(e){return e instanceof this},metaForProperty:function(e){var t=this.proto().__ember_meta__,r=t&&t.descs[e];return r._meta||{}},_computedProperties:_.computed(function(){Q=!0;var e,t=this.proto(),r=A(t).descs,n=[];for(var i in r)e=r[i],e instanceof z&&n.push({name:i,meta:e._meta});return n}).readOnly(),eachComputedProperty:function(e,t){for(var r,n,i={},a=w(this,"_computedProperties"),s=0,o=a.length;o>s;s++)r=a[s],n=r.name,e.call(t||this,r.name,r.meta||i)}});Z.ownerConstructor=J,_.config.overrideClassMixin&&_.config.overrideClassMixin(Z),J.ClassMixin=Z,Z.apply(J),J.reopen({didDefineProperty:function(e,t,r){if(Q!==!1&&r instanceof _.ComputedProperty){var n=_.meta(this.constructor).cache;void 0!==n._computedProperties&&(n._computedProperties=void 0)}}}),b["default"]=J}),e("ember-runtime/system/deferred",["ember-metal/core","ember-runtime/mixins/deferred","ember-metal/property_get","ember-runtime/system/object","exports"],function(e,t,r,n,i){"use strict";var a=(e["default"],t["default"]),s=(r.get,n["default"]),o=s.extend(a,{init:function(){this._super()}});o.reopenClass({promise:function(e,t){var r=o.create();return e.call(t,r),r}}),i["default"]=o}),e("ember-runtime/system/each_proxy",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/enumerable_utils","ember-metal/array","ember-runtime/mixins/array","ember-runtime/system/object","ember-metal/computed","ember-metal/observer","ember-metal/events","ember-metal/properties","ember-metal/property_events","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m){"use strict";function f(e,t,r,n,i){var a,s=r._objects;for(s||(s=r._objects={});--i>=n;){var o=e.objectAt(i);o&&(O(o,t,r,"contentKeyWillChange"),C(o,t,r,"contentKeyDidChange"),a=b(o),s[a]||(s[a]=[]),s[a].push(i))}}function d(e,t,r,n,i){var a=r._objects;a||(a=r._objects={});for(var s,o;--i>=n;){var u=e.objectAt(i);u&&(E(u,t,r,"contentKeyWillChange"),P(u,t,r,"contentKeyDidChange"),o=b(u),s=a[o],s[g.call(s,i)]=null)}}var v=(e["default"],t.get),b=(r.set,n.guidFor),y=i.forEach,g=a.indexOf,_=s["default"],w=o["default"],x=u.computed,C=l.addObserver,O=l.addBeforeObserver,E=l.removeBeforeObserver,P=l.removeObserver,A=(n.typeOf,c.watchedEvents),T=h.defineProperty,N=p.beginPropertyChanges,S=p.propertyDidChange,V=p.propertyWillChange,I=p.endPropertyChanges,k=p.changeProperties,D=w.extend(_,{init:function(e,t,r){this._super(),this._keyName=t,this._owner=r,this._content=e},objectAt:function(e){var t=this._content.objectAt(e);return t&&v(t,this._keyName)},length:x(function(){var e=this._content;return e?v(e,"length"):0})}),j=/^.+:(before|change)$/,M=w.extend({init:function(e){this._super(),this._content=e,e.addArrayObserver(this),y(A(this),function(e){this.didAddListener(e)},this)},unknownProperty:function(e){var t;return t=new D(this._content,e,this),T(this,e,null,t),this.beginObservingContentKey(e),t},arrayWillChange:function(e,t,r){var n,i,a=this._keys;i=r>0?t+r:-1,N(this);for(n in a)a.hasOwnProperty(n)&&(i>0&&d(e,n,this,t,i),V(this,n));V(this._content,"@each"),I(this)},arrayDidChange:function(e,t,r,n){var i,a=this._keys;i=n>0?t+n:-1,k(function(){for(var r in a)a.hasOwnProperty(r)&&(i>0&&f(e,r,this,t,i),S(this,r));S(this._content,"@each")},this)},didAddListener:function(e){j.test(e)&&this.beginObservingContentKey(e.slice(0,-7))},didRemoveListener:function(e){j.test(e)&&this.stopObservingContentKey(e.slice(0,-7))},beginObservingContentKey:function(e){var t=this._keys;if(t||(t=this._keys={}),t[e])t[e]++;else{t[e]=1;var r=this._content,n=v(r,"length");f(r,e,this,0,n)}},stopObservingContentKey:function(e){var t=this._keys;if(t&&t[e]>0&&--t[e]<=0){var r=this._content,n=v(r,"length");d(r,e,this,0,n)}},contentKeyWillChange:function(e,t){V(this,t)},contentKeyDidChange:function(e,t){S(this,t)}});m.EachArray=D,m.EachProxy=M}),e("ember-runtime/system/lazy_load",["ember-metal/core","ember-metal/array","ember-runtime/system/native_array","exports"],function(e,t,r,n){"use strict";function i(e,t){var r;u[e]=u[e]||s.A(),u[e].pushObject(t),(r=l[e])&&t(r)}function a(e,t){if(l[e]=t,"object"==typeof window&&"function"==typeof window.dispatchEvent&&"function"==typeof CustomEvent){var r=new CustomEvent(e,{detail:t,name:e});window.dispatchEvent(r)}u[e]&&o.call(u[e],function(e){e(t)})}var s=e["default"],o=t.forEach,u=s.ENV.EMBER_LOAD_HOOKS||{},l={};n.onLoad=i,n.runLoadHooks=a}),e("ember-runtime/system/namespace",["ember-metal/core","ember-metal/property_get","ember-metal/array","ember-metal/utils","ember-metal/mixin","ember-runtime/system/object","exports"],function(e,t,r,n,i,a,s){"use strict";function o(e,t,r){var n=e.length;x[e.join(".")]=t;for(var i in t)if(C.call(t,i)){var a=t[i];if(e[n]=i,a&&a.toString===h)a.toString=m(e.join(".")),a[E]=e.join(".");else if(a&&a.isNamespace){if(r[y(a)])continue;r[y(a)]=!0,o(e,a,r)}}e.length=n}function u(e,t){try{var r=e[t];return r&&r.isNamespace&&r}catch(n){}}function l(){var e,t=f.lookup;if(!w.PROCESSED)for(var r in t)O.test(r)&&(!t.hasOwnProperty||t.hasOwnProperty(r))&&(e=u(t,r),e&&(e[E]=r))}function c(e){var t=e.superclass;return t?t[E]?t[E]:c(t):void 0}function h(){f.BOOTED||this[E]||p();var e;if(this[E])e=this[E];else if(this._toString)e=this._toString;else{var t=c(this);e=t?"(subclass of "+t+")":"(unknown mixin)",this.toString=m(e)}return e}function p(){var e=!w.PROCESSED,t=f.anyUnprocessedMixins;if(e&&(l(),w.PROCESSED=!0),e||t){for(var r,n=w.NAMESPACES,i=0,a=n.length;a>i;i++)r=n[i],o([r.toString()],r,{});f.anyUnprocessedMixins=!1}}function m(e){return function(){return e}}var f=e["default"],d=t.get,v=r.indexOf,b=n.GUID_KEY,y=n.guidFor,g=i.Mixin,_=a["default"],w=_.extend({isNamespace:!0,init:function(){w.NAMESPACES.push(this),w.PROCESSED=!1},toString:function(){var e=d(this,"name")||d(this,"modulePrefix");return e?e:(l(),this[E])},nameClasses:function(){o([this.toString()],this,{})},destroy:function(){var e=w.NAMESPACES,t=this.toString();t&&(f.lookup[t]=void 0,delete w.NAMESPACES_BY_ID[t]),e.splice(v.call(e,this),1),this._super()}});w.reopenClass({NAMESPACES:[f],NAMESPACES_BY_ID:{},PROCESSED:!1,processAll:p,byName:function(e){return f.BOOTED||p(),x[e]}});var x=w.NAMESPACES_BY_ID,C={}.hasOwnProperty,O=/^[A-Z]/,E=f.NAME_KEY=b+"_name";g.prototype.toString=h,s["default"]=w}),e("ember-runtime/system/native_array",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/enumerable_utils","ember-metal/mixin","ember-metal/array","ember-runtime/mixins/array","ember-runtime/mixins/mutable_array","ember-runtime/mixins/observable","ember-runtime/mixins/copyable","ember-runtime/mixins/freezable","ember-runtime/copy","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p){"use strict";var m=e["default"],f=t.get,d=(r.set,n._replace),v=n.forEach,b=i.Mixin,y=a.indexOf,g=a.lastIndexOf,_=s["default"],w=o["default"],x=u["default"],C=l["default"],O=c.FROZEN_ERROR,E=h["default"],P=b.create(w,x,C,{get:function(e){return"length"===e?this.length:"number"==typeof e?this[e]:this._super(e)},objectAt:function(e){return this[e]},replace:function(e,t,r){if(this.isFrozen)throw O;var n=r?f(r,"length"):0;return this.arrayContentWillChange(e,t,n),0===n?this.splice(e,t):d(this,e,t,r),this.arrayContentDidChange(e,t,n),this},unknownProperty:function(e,t){var r;return void 0!==t&&void 0===r&&(r=this[e]=t),r},indexOf:y,lastIndexOf:g,copy:function(e){return e?this.map(function(e){return E(e,!0)}):this.slice()}}),A=["length"];v(P.keys(),function(e){Array.prototype[e]&&A.push(e)}),A.length>0&&(P=P.without.apply(P,A));var T=function(e){return void 0===e&&(e=[]),_.detect(e)?e:P.apply(e)};P.activate=function(){P.apply(Array.prototype),T=function(e){return e||[]}},(m.EXTEND_PROTOTYPES===!0||m.EXTEND_PROTOTYPES.Array)&&P.activate(),m.A=T,p.A=T,p.NativeArray=P,p["default"]=P}),e("ember-runtime/system/object",["ember-runtime/system/core_object","ember-runtime/mixins/observable","exports"],function(e,t,r){"use strict";var n=e["default"],i=t["default"],a=n.extend(i);a.toString=function(){return"Ember.Object"},r["default"]=a}),e("ember-runtime/system/object_proxy",["ember-runtime/system/object","ember-runtime/mixins/-proxy","exports"],function(e,t,r){"use strict";var n=e["default"],i=t["default"];r["default"]=n.extend(i)}),e("ember-runtime/system/set",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/is_none","ember-runtime/system/string","ember-runtime/system/core_object","ember-runtime/mixins/mutable_enumerable","ember-runtime/mixins/enumerable","ember-runtime/mixins/copyable","ember-runtime/mixins/freezable","ember-metal/error","ember-metal/property_events","ember-metal/mixin","ember-metal/computed","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m,f,d){"use strict";var v=(e["default"],t.get),b=r.set,y=n.guidFor,g=i.isNone,_=a.fmt,w=s["default"],x=o["default"],C=u["default"],O=l["default"],E=c.Freezable,P=c.FROZEN_ERROR,A=h["default"],T=p.propertyWillChange,N=p.propertyDidChange,S=m.aliasMethod,V=f.computed;d["default"]=w.extend(x,O,E,{length:0,clear:function(){if(this.isFrozen)throw new A(P);var e=v(this,"length");if(0===e)return this;var t;this.enumerableContentWillChange(e,0),T(this,"firstObject"),T(this,"lastObject");for(var r=0;e>r;r++)t=y(this[r]),delete this[t],delete this[r];return b(this,"length",0),N(this,"firstObject"),N(this,"lastObject"),this.enumerableContentDidChange(e,0),this},isEqual:function(e){if(!C.detect(e))return!1;var t=v(this,"length");if(v(e,"length")!==t)return!1;for(;--t>=0;)if(!e.contains(this[t]))return!1;return!0},add:S("addObject"),remove:S("removeObject"),pop:function(){if(v(this,"isFrozen"))throw new A(P);var e=this.length>0?this[this.length-1]:null;return this.remove(e),e},push:S("addObject"),shift:S("pop"),unshift:S("push"),addEach:S("addObjects"),removeEach:S("removeObjects"),init:function(e){this._super(),e&&this.addObjects(e)},nextObject:function(e){return this[e]},firstObject:V(function(){return this.length>0?this[0]:void 0}),lastObject:V(function(){return this.length>0?this[this.length-1]:void 0}),addObject:function(e){if(v(this,"isFrozen"))throw new A(P);if(g(e))return this;var t,r=y(e),n=this[r],i=v(this,"length");return n>=0&&i>n&&this[n]===e?this:(t=[e],this.enumerableContentWillChange(null,t),T(this,"lastObject"),i=v(this,"length"),this[r]=i,this[i]=e,b(this,"length",i+1),N(this,"lastObject"),this.enumerableContentDidChange(null,t),this)},removeObject:function(e){if(v(this,"isFrozen"))throw new A(P);if(g(e))return this;var t,r,n=y(e),i=this[n],a=v(this,"length"),s=0===i,o=i===a-1;return i>=0&&a>i&&this[i]===e&&(r=[e],this.enumerableContentWillChange(r,null),s&&T(this,"firstObject"),o&&T(this,"lastObject"),a-1>i&&(t=this[a-1],this[i]=t,this[y(t)]=i),delete this[n],delete this[a-1],b(this,"length",a-1),s&&N(this,"firstObject"),o&&N(this,"lastObject"),this.enumerableContentDidChange(r,null)),this},contains:function(e){return this[y(e)]>=0},copy:function(){var e=this.constructor,t=new e,r=v(this,"length");for(b(t,"length",r);--r>=0;)t[r]=this[r],t[y(this[r])]=r;return t},toString:function(){var e,t=this.length,r=[];for(e=0;t>e;e++)r[e]=this[e];return _("Ember.Set<%@>",[r.join(",")])}})}),e("ember-runtime/system/string",["ember-metal/core","ember-metal/utils","ember-metal/cache","exports"],function(e,t,r,n){"use strict";function i(e,t){var r=t;if(!f(r)||arguments.length>2){r=new Array(arguments.length-1);for(var n=1,i=arguments.length;i>n;n++)r[n-1]=arguments[n]}var a=0;return e.replace(/%@([0-9]+)?/g,function(e,t){return t=t?parseInt(t,10)-1:a++,e=r[t],null===e?"(null)":void 0===e?"":d(e)})}function a(e,t){return(!f(t)||arguments.length>2)&&(t=Array.prototype.slice.call(arguments,1)),e=m.STRINGS[e]||e,i(e,t)}function s(e){return e.split(/\s+/)}function o(e){return C.get(e)}function u(e){return y.get(e)}function l(e){return g.get(e)}function c(e){return _.get(e)}function h(e){return w.get(e) +}function p(e){return x.get(e)}var m=e["default"],f=t.isArray,d=t.inspect,v=r["default"],b=/[ _]/g,y=new v(1e3,function(e){return o(e).replace(b,"-")}),g=new v(1e3,function(e){return e.replace(E,function(e,t,r){return r?r.toUpperCase():""}).replace(/^([A-Z])/,function(e){return e.toLowerCase()})}),_=new v(1e3,function(e){for(var t=e.split("."),r=[],n=0,i=t.length;i>n;n++){var a=l(t[n]);r.push(a.charAt(0).toUpperCase()+a.substr(1))}return r.join(".")}),w=new v(1e3,function(e){return e.replace(P,"$1_$2").replace(A,"_").toLowerCase()}),x=new v(1e3,function(e){return e.charAt(0).toUpperCase()+e.substr(1)}),C=new v(1e3,function(e){return e.replace(O,"$1_$2").toLowerCase()}),O=/([a-z\d])([A-Z])/g,E=/(\-|_|\.|\s)+(.)?/g,P=/([a-z\d])([A-Z]+)/g,A=/\-|\s+/g;m.STRINGS={},n["default"]={fmt:i,loc:a,w:s,decamelize:o,dasherize:u,camelize:l,classify:c,underscore:h,capitalize:p},n.fmt=i,n.loc=a,n.w=s,n.decamelize=o,n.dasherize=u,n.camelize=l,n.classify=c,n.underscore=h,n.capitalize=p}),e("ember-runtime/system/subarray",["ember-metal/property_get","ember-metal/error","ember-metal/enumerable_utils","exports"],function(e,t,r,n){"use strict";function i(e,t){this.type=e,this.count=t}function a(e){arguments.length<1&&(e=0),this._operations=e>0?[new i(u,e)]:[]}var s=(e.get,t["default"]),o=r["default"],u="r",l="f";n["default"]=a,a.prototype={addItem:function(e,t){var r=-1,n=t?u:l,a=this;return this._findOperation(e,function(s,o,l,c,h){var p,m;n===s.type?++s.count:e===l?a._operations.splice(o,0,new i(n,1)):(p=new i(n,1),m=new i(s.type,c-e+1),s.count=e-l,a._operations.splice(o+1,0,p,m)),t&&(r=s.type===u?h+(e-l):h),a._composeAt(o)},function(e){a._operations.push(new i(n,1)),t&&(r=e),a._composeAt(a._operations.length-1)}),r},removeItem:function(e){var t=-1,r=this;return this._findOperation(e,function(n,i,a,s,o){n.type===u&&(t=o+(e-a)),n.count>1?--n.count:(r._operations.splice(i,1),r._composeAt(i))},function(){throw new s("Can't remove an item that has never been added.")}),t},_findOperation:function(e,t,r){var n,i,a,s,o,l=0;for(n=s=0,i=this._operations.length;i>n;s=o+1,++n){if(a=this._operations[n],o=s+a.count-1,e>=s&&o>=e)return void t(a,n,s,o,l);a.type===u&&(l+=a.count)}r(l)},_composeAt:function(e){var t,r=this._operations[e];r&&(e>0&&(t=this._operations[e-1],t.type===r.type&&(r.count+=t.count,this._operations.splice(e-1,1),--e)),er)){var n,a,o=this._findArrayOperation(e),u=o.operation,c=o.index,h=o.rangeStart;a=new i(l,r,t),u?o.split?(this._split(c,e-h,a),n=c+1):(this._operations.splice(c,0,a),n=c):(this._operations.push(a),n=c),this._composeInsert(n)}},removeItems:function(e,t){if(!(1>t)){var r,n,a=this._findArrayOperation(e),s=(a.operation,a.index),o=a.rangeStart;return r=new i(c,t),a.split?(this._split(s,e-o,r),n=s+1):(this._operations.splice(s,0,r),n=s),this._composeDelete(n)}},apply:function(e){var t=[],r=0;o(this._operations,function(n,i){e(n.items,r,n.type,i),n.type!==c&&(r+=n.count,t=t.concat(n.items))}),this._operations=[new i(u,t.length,t)]},_findArrayOperation:function(e){var t,r,n,i,s,o=!1;for(t=n=0,s=this._operations.length;s>t;++t)if(r=this._operations[t],r.type!==c){if(i=n+r.count-1,e===n)break;if(e>n&&i>=e){o=!0;break}n=i+1}return new a(r,t,o,n)},_split:function(e,t,r){var n=this._operations[e],a=n.items.slice(t),s=new i(n.type,a.length,a);n.count=t,n.items=n.items.slice(0,t),this._operations.splice(e+1,0,r,s)},_composeInsert:function(e){var t=this._operations[e],r=this._operations[e-1],n=this._operations[e+1],i=r&&r.type,a=n&&n.type;i===l?(r.count+=t.count,r.items=r.items.concat(t.items),a===l?(r.count+=n.count,r.items=r.items.concat(n.items),this._operations.splice(e,2)):this._operations.splice(e,1)):a===l&&(t.count+=n.count,t.items=t.items.concat(n.items),this._operations.splice(e+1,1))},_composeDelete:function(e){var t,r,n,i=this._operations[e],a=i.count,s=this._operations[e-1],o=s&&s.type,u=!1,h=[];o===c&&(i=s,e-=1);for(var p=e+1;a>0;++p)t=this._operations[p],r=t.type,n=t.count,r!==c?(n>a?(h=h.concat(t.items.splice(0,a)),t.count-=a,p-=1,n=a,a=0):(n===a&&(u=!0),h=h.concat(t.items),a-=n),r===l&&(i.count-=n)):i.count+=n;return i.count>0?this._operations.splice(e+1,p-1-e):this._operations.splice(e,u?2:1),h},toString:function(){var e="";return o(this._operations,function(t){e+=" "+t.type+":"+t.count}),e.substring(1)}}}),e("ember-views",["ember-runtime","ember-views/system/jquery","ember-views/system/utils","ember-views/system/render_buffer","ember-views/system/ext","ember-views/views/states","ember-views/views/core_view","ember-views/views/view","ember-views/views/container_view","ember-views/views/collection_view","ember-views/views/component","ember-views/system/event_dispatcher","ember-views/mixins/view_target_action_support","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m){"use strict";var f=e["default"],d=t["default"],v=r.isSimpleClick,b=n["default"],y=a.cloneStates,g=a.states,_=s["default"],w=o["default"],x=u["default"],C=l["default"],O=c["default"],E=h["default"],P=p["default"];f.$=d,f.ViewTargetActionSupport=P,f.RenderBuffer=b;var A=f.ViewUtils={};A.isSimpleClick=v,f.CoreView=_,f.View=w,f.View.states=g,f.View.cloneStates=y,f.ContainerView=x,f.CollectionView=C,f.Component=O,f.EventDispatcher=E,m["default"]=f}),e("ember-views/mixins/component_template_deprecation",["ember-metal/core","ember-metal/property_get","ember-metal/mixin","exports"],function(e,t,r,n){"use strict";var i=(e["default"],t.get),a=r.Mixin;n["default"]=a.create({willMergeMixin:function(e){this._super.apply(this,arguments);var t,r,n=e.layoutName||e.layout||i(this,"layoutName");e.templateName&&!n&&(t="templateName",r="layoutName",e.layoutName=e.templateName,delete e.templateName),e.template&&!n&&(t="template",r="layout",e.layout=e.template,delete e.template)}})}),e("ember-views/mixins/view_target_action_support",["ember-metal/mixin","ember-runtime/mixins/target_action_support","ember-metal/computed","exports"],function(e,t,r,n){"use strict";var i=e.Mixin,a=t["default"],s=r.computed,o=s.alias;n["default"]=i.create(a,{target:o("controller"),actionContext:o("context")})}),e("ember-views/system/action_manager",["exports"],function(e){"use strict";function t(){}t.registeredActions={},e["default"]=t}),e("ember-views/system/event_dispatcher",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/is_none","ember-metal/run_loop","ember-metal/utils","ember-runtime/system/string","ember-runtime/system/object","ember-views/system/jquery","ember-views/system/action_manager","ember-views/views/view","ember-metal/merge","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p){"use strict";var m=(e["default"],t.get),f=r.set,d=n.isNone,v=i["default"],b=a.typeOf,y=(s.fmt,o["default"]),g=u["default"],_=l["default"],w=c["default"],x=h["default"];p["default"]=y.extend({events:{touchstart:"touchStart",touchmove:"touchMove",touchend:"touchEnd",touchcancel:"touchCancel",keydown:"keyDown",keyup:"keyUp",keypress:"keyPress",mousedown:"mouseDown",mouseup:"mouseUp",contextmenu:"contextMenu",click:"click",dblclick:"doubleClick",mousemove:"mouseMove",focusin:"focusIn",focusout:"focusOut",mouseenter:"mouseEnter",mouseleave:"mouseLeave",submit:"submit",input:"input",change:"change",dragstart:"dragStart",drag:"drag",dragenter:"dragEnter",dragleave:"dragLeave",dragover:"dragOver",drop:"drop",dragend:"dragEnd"},rootElement:"body",canDispatchToEventManager:!0,setup:function(e,t){var r,n=m(this,"events");x(n,e||{}),d(t)||f(this,"rootElement",t),t=g(m(this,"rootElement")),t.addClass("ember-application");for(r in n)n.hasOwnProperty(r)&&this.setupHandler(t,r,n[r])},setupHandler:function(e,t,r){var n=this;e.on(t+".ember",".ember-view",function(e,t){var i=w.views[this.id],a=!0,s=n.canDispatchToEventManager?n._findNearestEventManager(i,r):null;return s&&s!==t?a=n._dispatchEvent(s,e,r,i):i&&(a=n._bubbleEvent(i,e,r)),a}),e.on(t+".ember","[data-ember-action]",function(e){var t=g(e.currentTarget).attr("data-ember-action"),n=_.registeredActions[t];return n&&n.eventName===r?n.handler(e):void 0})},_findNearestEventManager:function(e,t){for(var r=null;e&&(r=m(e,"eventManager"),!r||!r[t]);)e=m(e,"parentView");return r},_dispatchEvent:function(e,t,r,n){var i=!0,a=e[r];return"function"===b(a)?(i=v(e,a,t,n),t.stopPropagation()):i=this._bubbleEvent(n,t,r),i},_bubbleEvent:function(e,t,r){return v(e,e.handleEvent,r,t)},destroy:function(){var e=m(this,"rootElement");return g(e).off(".ember","**").removeClass("ember-application"),this._super()},toString:function(){return"(EventDispatcher)"}})}),e("ember-views/system/ext",["ember-metal/run_loop"],function(e){"use strict";{var t=e["default"];t.queues}t._addQueue("render","actions"),t._addQueue("afterRender","render")}),e("ember-views/system/jquery",["ember-metal/core","ember-runtime/system/string","ember-metal/enumerable_utils","exports"],function(e,t,n,i){"use strict";var a=e["default"],s=t.w,o=n.forEach,u=a.imports&&a.imports.jQuery||this&&this.jQuery;if(u||"function"!=typeof r||(u=r("jquery")),u){var l=s("dragstart drag dragenter dragleave dragover drop dragend");o(l,function(e){u.event.fixHooks[e]={props:["dataTransfer"]}})}i["default"]=u}),e("ember-views/system/render_buffer",["ember-views/system/jquery","morph","ember-metal/core","ember-metal/platform","exports"],function(e,t,r,n,i){"use strict";function a(e,t){if("TABLE"===t.tagName){var r=f.exec(e);if(r)return m[r[1].toLowerCase()]}}function s(){this.seen=p(null),this.list=[]}function o(e){return e&&d.test(e)?e.replace(v,""):e}function u(e){var t={"<":"<",">":">",'"':""","'":"'","`":"`"},r=function(e){return t[e]||"&"},n=e.toString();return y.test(n)?n.replace(b,r):n}function l(e,t){this.tagName=e,this._outerContextualElement=t,this.buffer=null,this.childViews=[],this.dom=new h}var c=e["default"],h=t.DOMHelper,p=(r["default"],n.create),m={tr:document.createElement("tbody"),col:document.createElement("colgroup")},f=/(?:"'`]/g,y=/[&<>"'`]/,g=function(){var e=document.createElement("div"),t=document.createElement("input");return t.setAttribute("name","foo"),e.appendChild(t),!!e.innerHTML.match("foo")}();i["default"]=function(e,t){return new l(e,t)},l.prototype={reset:function(e,t){this.tagName=e,this.buffer=null,this._element=null,this._outerContextualElement=t,this.elementClasses=null,this.elementId=null,this.elementAttributes=null,this.elementProperties=null,this.elementTag=null,this.elementStyle=null,this.childViews.length=0},_element:null,_outerContextualElement:null,elementClasses:null,classes:null,elementId:null,elementAttributes:null,elementProperties:null,elementTag:null,elementStyle:null,pushChildView:function(e){var t=this.childViews.length;this.childViews[t]=e,this.push("")},hydrateMorphs:function(e){for(var t=this.childViews,r=this._element,n=0,i=t.length;i>n;n++){var a=t[n],s=r.querySelector("#morph-"+n),o=s.parentNode;a._morph=this.dom.insertMorphBefore(o,s,1===o.nodeType?o:e),o.removeChild(s)}},push:function(e){return null===this.buffer&&(this.buffer=""),this.buffer+=e,this},addClass:function(e){return this.elementClasses=this.elementClasses||new s,this.elementClasses.add(e),this.classes=this.elementClasses.list,this},setClasses:function(e){this.elementClasses=null;var t,r=e.length;for(t=0;r>t;t++)this.addClass(e[t])},id:function(e){return this.elementId=e,this},attr:function(e,t){var r=this.elementAttributes=this.elementAttributes||{};return 1===arguments.length?r[e]:(r[e]=t,this)},removeAttr:function(e){var t=this.elementAttributes;return t&&delete t[e],this},prop:function(e,t){var r=this.elementProperties=this.elementProperties||{};return 1===arguments.length?r[e]:(r[e]=t,this)},removeProp:function(e){var t=this.elementProperties;return t&&delete t[e],this},style:function(e,t){return this.elementStyle=this.elementStyle||{},this.elementStyle[e]=t,this},generateElement:function(){var e,t,r,n=this.tagName,i=this.elementId,a=this.classes,s=this.elementAttributes,l=this.elementProperties,h=this.elementStyle,p="";r=s&&s.name&&!g?"<"+o(n)+' name="'+u(s.name)+'">':n;var m=this.dom.createElement(r,this.outerContextualElement()),f=c(m);if(i&&(this.dom.setAttribute(m,"id",i),this.elementId=null),a&&(this.dom.setAttribute(m,"class",a.join(" ")),this.classes=null,this.elementClasses=null),h){for(t in h)h.hasOwnProperty(t)&&(p+=t+":"+h[t]+";");this.dom.setAttribute(m,"style",p),this.elementStyle=null}if(s){for(e in s)s.hasOwnProperty(e)&&this.dom.setAttribute(m,e,s[e]);this.elementAttributes=null}if(l){for(t in l)l.hasOwnProperty(t)&&f.prop(t,l[t]);this.elementProperties=null}this._element=m},element:function(){var e=this.innerContent();if(null===e)return this._element;var t=this.innerContextualElement(e);this.dom.detectNamespace(t),this._element||(this._element=document.createDocumentFragment());for(var r=this.dom.parseHTML(e,t);r[0];)this._element.appendChild(r[0]);return this.hydrateMorphs(t),this._element},string:function(){if(this._element){var e=this.element(),t=e.outerHTML;return"undefined"==typeof t?c("
    ").append(e).html():t}return this.innerString()},outerContextualElement:function(){return this._outerContextualElement||(this.outerContextualElement=document.body),this._outerContextualElement},innerContextualElement:function(e){var t;t=this._element&&1===this._element.nodeType?this._element:this.outerContextualElement();var r;return e&&(r=a(e,t)),r||t},innerString:function(){var e=this.innerContent();return e&&!e.nodeType?e:void 0},innerContent:function(){return this.buffer}}}),e("ember-views/system/renderer",["ember-metal-views/renderer","ember-metal/platform","ember-views/system/render_buffer","ember-metal/run_loop","ember-metal/property_set","ember-metal/instrumentation","exports"],function(e,t,r,n,i,a,s){"use strict";function o(){this.buffer=c(),u.call(this)}var u=e["default"],l=t.create,c=r["default"],h=n["default"],p=i.set,m=a._instrumentStart,f=a.subscribers;o.prototype=l(u.prototype),o.prototype.constructor=o;o.prototype.scheduleRender=function(e,t){return h.scheduleOnce("render",e,t)},o.prototype.cancelRender=function(e){h.cancel(e)},o.prototype.createChildViewsMorph=function(e,t){if(e.createChildViewsMorph)return e.createChildViewsMorph(t);var r=t;return""===e.tagName?e._morph?e._childViewsMorph=e._morph:(r=document.createDocumentFragment(),e._childViewsMorph=this._dom.appendMorph(r)):e._childViewsMorph=this._dom.createMorph(r,r.lastChild,null),r},o.prototype.createElement=function(e,t){var r=e.tagName;(null===r||void 0===r)&&(r="div");var n=e.buffer=this.buffer;n.reset(r,t),e.beforeRender&&e.beforeRender(n),""!==e.tagName&&(e.applyAttributesToBuffer&&e.applyAttributesToBuffer(n),n.generateElement()),e.render&&e.render(n),e.afterRender&&e.afterRender(n);var i=n.element();return e.isContainer&&this.createChildViewsMorph(e,i),e.buffer=null,i&&1===i.nodeType&&p(e,"element",i),i},o.prototype.destroyView=function(e){e.removedFromDOM=!0,e.destroy()},o.prototype.childViews=function(e){return e._childViews},u.prototype.willCreateElement=function(e){f.length&&e.instrumentDetails&&(e._instrumentEnd=m("render."+e.instrumentName,function(){var t={};return e.instrumentDetails(t),t})),e._transitionTo&&e._transitionTo("inBuffer")},u.prototype.didCreateElement=function(e){e._transitionTo&&e._transitionTo("hasElement"),e._instrumentEnd&&e._instrumentEnd()},u.prototype.willInsertElement=function(e){e.trigger&&e.trigger("willInsertElement")},u.prototype.didInsertElement=function(e){e._transitionTo&&e._transitionTo("inDOM"),e.trigger&&e.trigger("didInsertElement")},u.prototype.willRemoveElement=function(){},u.prototype.willDestroyElement=function(e){e.trigger&&e.trigger("willDestroyElement"),e.trigger&&e.trigger("willClearRender")},u.prototype.didDestroyElement=function(e){p(e,"element",null),e._transitionTo&&e._transitionTo("preRender")},s["default"]=o}),e("ember-views/system/utils",["exports"],function(e){"use strict";function t(e){var t=e.shiftKey||e.metaKey||e.altKey||e.ctrlKey,r=e.which>1;return!t&&!r}e.isSimpleClick=t}),e("ember-views/views/collection_view",["ember-metal/core","ember-metal/platform","ember-metal/binding","ember-metal/merge","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/string","ember-views/views/container_view","ember-views/views/core_view","ember-views/views/view","ember-metal/mixin","ember-handlebars/ext","ember-runtime/mixins/array","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m){"use strict";var f=(e["default"],t.create,r.isGlobalPath),d=(n["default"],i.get),v=a.set,b=(s.fmt,o["default"]),y=u["default"],g=l["default"],_=c.observer,w=c.beforeObserver,x=h.handlebarsGetView,C=(p["default"],b.extend({content:null,emptyViewClass:g,emptyView:null,itemViewClass:g,init:function(){var e=this._super();return this._contentDidChange(),e},_contentWillChange:w("content",function(){var e=this.get("content");e&&e.removeArrayObserver(this);var t=e?d(e,"length"):0;this.arrayWillChange(e,0,t)}),_contentDidChange:_("content",function(){var e=d(this,"content");e&&(this._assertArrayLike(e),e.addArrayObserver(this));var t=e?d(e,"length"):0;this.arrayDidChange(e,0,null,t)}),_assertArrayLike:function(){},destroy:function(){if(this._super()){var e=d(this,"content");return e&&e.removeArrayObserver(this),this._createdEmptyView&&this._createdEmptyView.destroy(),this}},arrayWillChange:function(e,t,r){var n=d(this,"emptyView");n&&n instanceof g&&n.removeFromParent();var i,a,s=this._childViews;for(a=t+r-1;a>=t;a--)i=s[a],i.destroy()},arrayDidChange:function(e,t,r,n){var i,a,s,o,u,l,c=[];if(o=e?d(e,"length"):0)for(u=d(this,"itemViewClass"),u=x(e,u,this.container),s=t;t+n>s;s++)a=e.objectAt(s),i=this.createChildView(u,{content:a,contentIndex:s}),c.push(i);else{if(l=d(this,"emptyView"),!l)return;"string"==typeof l&&f(l)&&(l=d(l)||l),l=this.createChildView(l),c.push(l),v(this,"emptyView",l),y.detect(l)&&(this._createdEmptyView=l)}this.replace(t,0,c)},createChildView:function(e,t){e=this._super(e,t);var r=d(e,"tagName");return(null===r||void 0===r)&&(r=C.CONTAINER_MAP[d(this,"tagName")],v(e,"tagName",r)),e}}));C.CONTAINER_MAP={ul:"li",ol:"li",table:"tr",thead:"tr",tbody:"tr",tfoot:"tr",tr:"td",select:"option"},m["default"]=C}),e("ember-views/views/component",["ember-metal/core","ember-views/mixins/component_template_deprecation","ember-runtime/mixins/target_action_support","ember-views/views/view","ember-metal/property_get","ember-metal/property_set","ember-metal/is_none","ember-metal/computed","exports"],function(e,t,r,n,i,a,s,o,u){"use strict";var l=e["default"],c=t["default"],h=r["default"],p=n["default"],m=i.get,f=a.set,d=(s.isNone,o.computed),v=Array.prototype.slice,b=p.extend(h,c,{instrumentName:"component",instrumentDisplay:d(function(){return this._debugContainerKey?"{{"+this._debugContainerKey.split(":")[1]+"}}":void 0}),init:function(){this._super(),f(this,"origContext",m(this,"context")),f(this,"context",this),f(this,"controller",this)},defaultLayout:function(e,t){l.Handlebars.helpers["yield"].call(e,t)},template:d(function(e,t){if(void 0!==t)return t;var r=m(this,"templateName"),n=this.templateForName(r,"template");return n||m(this,"defaultTemplate")}).property("templateName"),templateName:null,cloneKeywords:function(){return{view:this,controller:this}},_yield:function(e,t){var r=t.data.view,n=this._parentView,i=m(this,"template");i&&r.appendChild(p,{isVirtual:!0,tagName:"",_contextView:n,template:i,context:t.data.insideGroup?m(this,"origContext"):m(n,"context"),controller:m(n,"controller"),templateData:{keywords:n.cloneKeywords(),insideGroup:t.data.insideGroup}})},targetObject:d(function(){var e=m(this,"_parentView");return e?m(e,"controller"):null}).property("_parentView"),sendAction:function(e){var t,r=v.call(arguments,1);t=void 0===e?m(this,"action"):m(this,e),void 0!==t&&this.triggerAction({action:t,actionContext:r})}});u["default"]=b}),e("ember-views/views/container_view",["ember-metal/core","ember-metal/merge","ember-runtime/mixins/mutable_array","ember-metal/property_get","ember-metal/property_set","ember-views/views/view","ember-views/views/states","ember-metal/error","ember-metal/enumerable_utils","ember-metal/computed","ember-metal/run_loop","ember-metal/properties","ember-views/system/render_buffer","ember-metal/mixin","ember-runtime/system/native_array","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m,f,d){"use strict";var v=e["default"],b=t["default"],y=r["default"],g=n.get,_=i.set,w=a["default"],x=s.cloneStates,C=s.states,O=o["default"],E=u.forEach,P=l.computed,A=c["default"],T=h.defineProperty,N=(p["default"],m.observer),S=m.beforeObserver,V=(f.A,x(C)),I=w.extend(y,{isContainer:!0,_states:V,willWatchProperty:function(){},init:function(){this._super();var e=g(this,"childViews");T(this,"childViews",w.childViewsProperty);var t=this._childViews;E(e,function(e,r){var n;"string"==typeof e?(n=g(this,e),n=this.createChildView(n),_(this,e,n)):n=this.createChildView(e),t[r]=n},this);var r=g(this,"currentView");r&&(t.length||(t=this._childViews=this._childViews.slice()),t.push(this.createChildView(r)))},replace:function(e,t,r){var n=r?g(r,"length"):0;if(this.arrayContentWillChange(e,t,n),this.childViewsWillChange(this._childViews,e,t),0===n)this._childViews.splice(e,t);else{var i=[e,t].concat(r);r.length&&!this._childViews.length&&(this._childViews=this._childViews.slice()),this._childViews.splice.apply(this._childViews,i)}return this.arrayContentDidChange(e,t,n),this.childViewsDidChange(this._childViews,e,t,n),this},objectAt:function(e){return this._childViews[e]},length:P(function(){return this._childViews.length})["volatile"](),render:function(){},instrumentName:"container",childViewsWillChange:function(e,t,r){if(this.propertyWillChange("childViews"),r>0){var n=e.slice(t,t+r);this.currentState.childViewsWillChange(this,e,t,r),this.initializeViews(n,null,null)}},removeChild:function(e){return this.removeObject(e),this},childViewsDidChange:function(e,t,r,n){if(n>0){var i=e.slice(t,t+n);this.initializeViews(i,this,g(this,"templateData")),this.currentState.childViewsDidChange(this,e,t,n)}this.propertyDidChange("childViews")},initializeViews:function(e,t,r){E(e,function(e){_(e,"_parentView",t),!e.container&&t&&_(e,"container",t.container),g(e,"templateData")||_(e,"templateData",r)})},currentView:null,_currentViewWillChange:S("currentView",function(){var e=g(this,"currentView");e&&e.destroy()}),_currentViewDidChange:N("currentView",function(){var e=g(this,"currentView");e&&this.pushObject(e)}),_ensureChildrenAreInDOM:function(){this.currentState.ensureChildrenAreInDOM(this)}});b(V._default,{childViewsWillChange:v.K,childViewsDidChange:v.K,ensureChildrenAreInDOM:v.K}),b(V.inBuffer,{childViewsDidChange:function(){throw new O("You cannot modify child views while in the inBuffer state")}}),b(V.hasElement,{childViewsWillChange:function(e,t,r,n){for(var i=r;r+n>i;i++)t[i].remove()},childViewsDidChange:function(e){A.scheduleOnce("render",e,"_ensureChildrenAreInDOM")},ensureChildrenAreInDOM:function(e){var t,r,n,i=e._childViews,a=e._renderer;for(t=0,r=i.length;r>t;t++)n=i[t],n._elementCreated||a.renderTree(n,e,t)}}),d["default"]=I}),e("ember-views/views/core_view",["ember-views/system/renderer","ember-views/views/states","ember-runtime/system/object","ember-runtime/mixins/evented","ember-runtime/mixins/action_handler","ember-metal/property_get","ember-metal/property_set","ember-metal/computed","ember-metal/utils","ember-metal/instrumentation","exports"],function(e,t,r,n,a,s,o,u,l,c,h){"use strict";var p=e["default"],m=t.cloneStates,f=t.states,d=r["default"],v=n["default"],b=a["default"],y=s.get,g=(o.set,u.computed),_=l.typeOf,w=(c.instrument,d.extend(v,b,{isView:!0,isVirtual:!1,isContainer:!1,_states:m(f),init:function(){this._super(),this._transitionTo("preRender"),this._isVisible=y(this,"isVisible")},parentView:g("_parentView",function(){var e=this._parentView;return e&&e.isVirtual?y(e,"parentView"):e}),_state:null,_parentView:null,concreteView:g("parentView",function(){return this.isVirtual?y(this,"parentView.concreteView"):this}),instrumentName:"core_view",instrumentDetails:function(e){e.object=this.toString(),e.containerKey=this._debugContainerKey,e.view=this},trigger:function(){this._super.apply(this,arguments);var e=arguments[0],t=this[e];if(t){for(var r=arguments.length,n=new Array(r-1),i=1;r>i;i++)n[i-1]=arguments[i];return t.apply(this,n)}},has:function(e){return"function"===_(this[e])||this._super(e)},destroy:function(){var e=this._parentView;if(this._super())return!this.removedFromDOM&&this._renderer&&this._renderer.remove(this,!0),e&&e.removeChild(this),this._transitionTo("destroying",!1),this},clearRenderedChildren:i.K,_transitionTo:i.K,destroyElement:i.K}));w.reopenClass({renderer:new p}),h["default"]=w}),e("ember-views/views/states",["ember-metal/platform","ember-metal/merge","ember-views/views/states/default","ember-views/views/states/pre_render","ember-views/views/states/in_buffer","ember-views/views/states/has_element","ember-views/views/states/in_dom","ember-views/views/states/destroying","exports"],function(e,t,r,n,i,a,s,o,u){"use strict";function l(e){var t={};t._default={},t.preRender=c(t._default),t.destroying=c(t._default),t.inBuffer=c(t._default),t.hasElement=c(t._default),t.inDOM=c(t.hasElement);for(var r in e)e.hasOwnProperty(r)&&h(t[r],e[r]);return t}var c=e.create,h=t["default"],p=r["default"],m=n["default"],f=i["default"],d=a["default"],v=s["default"],b=o["default"];u.cloneStates=l;var y={_default:p,preRender:m,inDOM:v,inBuffer:f,hasElement:d,destroying:b};u.states=y}),e("ember-views/views/states/default",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/run_loop","ember-metal/error","exports"],function(e,t,r,n,i,a){"use strict";var s=e["default"],o=(t.get,r.set,n["default"],i["default"]);a["default"]={appendChild:function(){throw new o("You can't use appendChild outside of the rendering process")},$:function(){return void 0},getElement:function(){return null},handleEvent:function(){return!0},destroyElement:function(e){return e._renderer&&e._renderer.remove(e,!1),e},rerender:s.K,invokeObserver:s.K}}),e("ember-views/views/states/destroying",["ember-metal/merge","ember-metal/platform","ember-runtime/system/string","ember-views/views/states/default","ember-metal/error","exports"],function(e,t,r,n,i,a){"use strict";var s=e["default"],o=t.create,u=r.fmt,l=n["default"],c=i["default"],h="You can't call %@ on a view being destroyed",p=o(l);s(p,{appendChild:function(){throw new c(u(h,["appendChild"]))},rerender:function(){throw new c(u(h,["rerender"]))},destroyElement:function(){throw new c(u(h,["destroyElement"]))}}),a["default"]=p}),e("ember-views/views/states/has_element",["ember-views/views/states/default","ember-metal/run_loop","ember-metal/merge","ember-metal/platform","ember-views/system/jquery","ember-metal/error","ember-metal/property_get","ember-metal/property_set","exports"],function(e,t,r,n,i,a,s,o,u){"use strict";var l=e["default"],c=t["default"],h=r["default"],p=n.create,m=i["default"],f=a["default"],d=s.get,v=(o.set,p(l));h(v,{$:function(e,t){var r=e.get("concreteView").element;return t?m(t,r):m(r)},getElement:function(e){var t=d(e,"parentView");return t&&(t=d(t,"element")),t?e.findElementInParentElement(t):m("#"+d(e,"elementId"))[0]},rerender:function(e){if(e._root._morph&&!e._elementInserted)throw new f("Something you did caused a view to re-render after it rendered but before it was inserted into the DOM.");c.scheduleOnce("render",function(){e.isDestroying||e._renderer.renderTree(e,e._parentView)})},destroyElement:function(e){return e._renderer.remove(e,!1),e},handleEvent:function(e,t,r){return e.has(t)?e.trigger(t,r):!0},invokeObserver:function(e,t){t.call(e)}}),u["default"]=v}),e("ember-views/views/states/in_buffer",["ember-views/views/states/default","ember-metal/error","ember-metal/core","ember-metal/platform","ember-metal/merge","exports"],function(e,t,r,n,i,a){"use strict";var s=e["default"],o=t["default"],u=r["default"],l=n.create,c=i["default"],h=l(s);c(h,{$:function(e){return e.rerender(),u.$()},rerender:function(){throw new o("Something you did caused a view to re-render after it rendered but before it was inserted into the DOM.")},appendChild:function(e,t,r){var n=e.buffer,i=e._childViews;return t=e.createChildView(t,r),i.length||(i=e._childViews=i.slice()),i.push(t),t._morph||n.pushChildView(t),e.propertyDidChange("childViews"),t},invokeObserver:function(e,t){t.call(e)}}),a["default"]=h}),e("ember-views/views/states/in_dom",["ember-metal/core","ember-metal/platform","ember-metal/merge","ember-metal/error","ember-views/views/states/has_element","exports"],function(e,r,n,i,a,s){"use strict";var o,u=(e["default"],r.create),l=n["default"],c=i["default"],h=a["default"],p=u(h);l(p,{enter:function(e){o||(o=t("ember-views/views/view")["default"]),e.isVirtual||(o.views[e.elementId]=e),e.addBeforeObserver("elementId",function(){throw new c("Changing a view's elementId after creation is not allowed")})},exit:function(e){o||(o=t("ember-views/views/view")["default"]),this.isVirtual||delete o.views[e.elementId]}}),s["default"]=p}),e("ember-views/views/states/pre_render",["ember-views/views/states/default","ember-metal/platform","ember-metal/merge","ember-views/system/jquery","exports"],function(e,t,r,n,i){"use strict";var a=e["default"],s=t.create,o=(r["default"],n["default"],s(a));i["default"]=o}),e("ember-views/views/view",["ember-metal/core","ember-runtime/mixins/evented","ember-runtime/system/object","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/set_properties","ember-metal/run_loop","ember-metal/observer","ember-metal/properties","ember-metal/utils","ember-metal/computed","ember-metal/mixin","ember-metal/is_none","ember-metal/deprecate_property","ember-runtime/system/native_array","ember-runtime/system/string","ember-metal/enumerable_utils","ember-runtime/copy","ember-metal/binding","ember-metal/property_events","ember-views/system/jquery","ember-views/system/ext","ember-views/views/core_view","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m,f,d,v,b,y,g,_,w,x,C,O){"use strict";var E=e["default"],P=t["default"],A=r["default"],T=n["default"],N=i.get,S=a.set,V=s["default"],I=o["default"],k=u.addObserver,D=u.removeObserver,j=l.defineProperty,M=l.deprecateProperty,R=c.guidFor,L=(c.meta,h.computed),H=p.observer,z=c.typeOf,q=c.isArray,F=m.isNone,B=p.Mixin,M=f.deprecateProperty,U=d.A,K=v.dasherize,W=b.forEach,G=b.addObject,Q=b.removeObject,$=p.beforeObserver,Y=y["default"],J=g.isGlobalPath,Z=_.propertyWillChange,X=_.propertyDidChange,et=w["default"],tt=C["default"],rt=L(function(){var e=this._childViews,t=U();return W(e,function(e){var r;e.isVirtual?(r=N(e,"childViews"))&&t.pushObjects(r):t.push(e)}),t.replace=function(){throw new T("childViews is immutable")},t});E.TEMPLATES={};var nt=[],it=tt.extend({concatenatedProperties:["classNames","classNameBindings","attributeBindings"],isView:!0,templateName:null,layoutName:null,instrumentDisplay:L(function(){return this.helperName?"{{"+this.helperName+"}}":void 0}),template:L("templateName",function(e,t){if(void 0!==t)return t; +var r=N(this,"templateName"),n=this.templateForName(r,"template");return n||N(this,"defaultTemplate")}),controller:L("_parentView",function(){var e=N(this,"_parentView");return e?N(e,"controller"):null}),layout:L(function(){var e=N(this,"layoutName"),t=this.templateForName(e,"layout");return t||N(this,"defaultLayout")}).property("layoutName"),_yield:function(e,t){var r=N(this,"template");r&&r(e,t)},templateForName:function(e){if(e){if(!this.container)throw new T("Container was not found when looking up a views template. This is most likely due to manually instantiating an Ember.View. See: http://git.io/EKPpnA");return this.container.lookup("template:"+e)}},context:L(function(e,t){return 2===arguments.length?(S(this,"_context",t),t):N(this,"_context")})["volatile"](),_context:L(function(){var e,t;return(t=N(this,"controller"))?t:(e=this._parentView,e?N(e,"_context"):null)}),_contextDidChange:H("context",function(){this.rerender()}),isVisible:!0,childViews:rt,_childViews:nt,_childViewsWillChange:$("childViews",function(){if(this.isVirtual){var e=N(this,"parentView");e&&Z(e,"childViews")}}),_childViewsDidChange:H("childViews",function(){if(this.isVirtual){var e=N(this,"parentView");e&&X(e,"childViews")}}),nearestInstanceOf:function(e){for(var t=N(this,"parentView");t;){if(t instanceof e)return t;t=N(t,"parentView")}},nearestOfType:function(e){for(var t=N(this,"parentView"),r=e instanceof B?function(t){return e.detect(t)}:function(t){return e.detect(t.constructor)};t;){if(r(t))return t;t=N(t,"parentView")}},nearestWithProperty:function(e){for(var t=N(this,"parentView");t;){if(e in t)return t;t=N(t,"parentView")}},nearestChildOf:function(e){for(var t=N(this,"parentView");t;){if(N(t,"parentView")instanceof e)return t;t=N(t,"parentView")}},_parentViewDidChange:H("_parentView",function(){this.isDestroying||(this.trigger("parentViewDidChange"),N(this,"parentView.controller")&&!N(this,"controller")&&this.notifyPropertyChange("controller"))}),_controllerDidChange:H("controller",function(){this.isDestroying||(this.rerender(),this.forEachChildView(function(e){e.propertyDidChange("controller")}))}),cloneKeywords:function(){var e=N(this,"templateData"),t=e?Y(e.keywords):{};return S(t,"view",this.isVirtual?t.view:this),S(t,"_view",this),S(t,"controller",N(this,"controller")),t},render:function(e){var t=N(this,"layout")||N(this,"template");if(t){var r,n=N(this,"context"),i=this.cloneKeywords(),a={view:this,buffer:e,isRenderData:!0,keywords:i,insideGroup:N(this,"templateData.insideGroup")};r=t(n,{data:a}),void 0!==r&&e.push(r)}},rerender:function(){return this.currentState.rerender(this)},_applyClassNameBindings:function(e){var t,r,n,i=this.classNames;W(e,function(e){var a,s=it._parsePropertyPath(e),o=function(){r=this._classStringForProperty(e),t=this.$(),a&&(t.removeClass(a),i.removeObject(a)),r?(t.addClass(r),a=r):a=null};n=this._classStringForProperty(e),n&&(G(i,n),a=n),this.registerObserver(this,s.path,o),this.one("willClearRender",function(){a&&(i.removeObject(a),a=null)})},this)},_unspecifiedAttributeBindings:null,_applyAttributeBindings:function(e,t){var r,n=this._unspecifiedAttributeBindings=this._unspecifiedAttributeBindings||{};W(t,function(t){var i=t.split(":"),a=i[0],s=i[1]||a;a in this?(this._setupAttributeBindingObservation(a,s),r=N(this,a),it.applyAttributeBindings(e,s,r)):n[a]=s},this),this.setUnknownProperty=this._setUnknownProperty},_setupAttributeBindingObservation:function(e,t){var r,n,i=function(){n=this.$(),r=N(this,e),it.applyAttributeBindings(n,t,r)};this.registerObserver(this,e,i)},setUnknownProperty:null,_setUnknownProperty:function(e,t){var r=this._unspecifiedAttributeBindings&&this._unspecifiedAttributeBindings[e];return r&&this._setupAttributeBindingObservation(e,r),j(this,e),S(this,e,t)},_classStringForProperty:function(e){var t=it._parsePropertyPath(e),r=t.path,n=N(this,r);return void 0===n&&J(r)&&(n=N(E.lookup,r)),it._classStringForValue(r,n,t.className,t.falsyClassName)},element:null,$:function(e){return this.currentState.$(this,e)},mutateChildViews:function(e){for(var t,r=this._childViews,n=r.length;--n>=0;)t=r[n],e(this,t,n);return this},forEachChildView:function(e){var t=this._childViews;if(!t)return this;var r,n,i=t.length;for(n=0;i>n;n++)r=t[n],e(r);return this},appendTo:function(e){var t=et(e);return this.constructor.renderer.appendTo(this,t[0]),this},replaceIn:function(e){var t=et(e);return this.constructor.renderer.replaceIn(this,t[0]),this},append:function(){return this.appendTo(document.body)},remove:function(){this.removedFromDOM||this.destroyElement()},elementId:null,findElementInParentElement:function(e){var t="#"+this.elementId;return et(t)[0]||et(t,e)[0]},createElement:function(){return this.element?this:(this._didCreateElementWithoutMorph=!0,this.constructor.renderer.renderTree(this),this)},willInsertElement:E.K,didInsertElement:E.K,willClearRender:E.K,destroyElement:function(){return this.currentState.destroyElement(this)},willDestroyElement:E.K,parentViewDidChange:E.K,instrumentName:"view",instrumentDetails:function(e){e.template=N(this,"templateName"),this._super(e)},beforeRender:function(){},afterRender:function(){},applyAttributesToBuffer:function(e){var t=N(this,"classNameBindings");t.length&&this._applyClassNameBindings(t);var r=N(this,"attributeBindings");r.length&&this._applyAttributeBindings(e,r),e.setClasses(this.classNames),e.id(this.elementId);var n=N(this,"ariaRole");n&&e.attr("role",n),N(this,"isVisible")===!1&&e.style("display","none")},tagName:null,ariaRole:null,classNames:["ember-view"],classNameBindings:nt,attributeBindings:nt,init:function(){this.isVirtual||this.elementId||(this.elementId=R(this)),this._super(),this._childViews=this._childViews.slice(),this.classNameBindings=U(this.classNameBindings.slice()),this.classNames=U(this.classNames.slice())},appendChild:function(e,t){return this.currentState.appendChild(this,e,t)},removeChild:function(e){if(!this.isDestroying){S(e,"_parentView",null);var t=this._childViews;return Q(t,e),this.propertyDidChange("childViews"),this}},removeAllChildren:function(){return this.mutateChildViews(function(e,t){e.removeChild(t)})},destroyAllChildren:function(){return this.mutateChildViews(function(e,t){t.destroy()})},removeFromParent:function(){var e=this._parentView;return this.remove(),e&&e.removeChild(this),this},destroy:function(){var e=(this._childViews,N(this,"parentView")),t=this.viewName;return this._super()?(t&&e&&e.set(t,null),this):void 0},createChildView:function(e,t){if(!e)throw new TypeError("createChildViews first argument must exist");if(e.isView&&e._parentView===this&&e.container===this.container)return e;if(t=t||{},t._parentView=this,tt.detect(e))t.templateData=t.templateData||N(this,"templateData"),t.container=this.container,e=e.create(t),e.viewName&&S(N(this,"concreteView"),e.viewName,e);else if("string"==typeof e){var r="view:"+e,n=this.container.lookupFactory(r);t.templateData=N(this,"templateData"),e=n.create(t)}else t.container=this.container,N(e,"templateData")||(t.templateData=N(this,"templateData")),V(e,t);return e},becameVisible:E.K,becameHidden:E.K,_isVisibleDidChange:H("isVisible",function(){this._isVisible!==N(this,"isVisible")&&I.scheduleOnce("render",this,this._toggleVisibility)}),_toggleVisibility:function(){var e=this.$(),t=N(this,"isVisible");this._isVisible!==t&&(this._isVisible=t,e&&(e.toggle(t),this._isAncestorHidden()||(t?this._notifyBecameVisible():this._notifyBecameHidden())))},_notifyBecameVisible:function(){this.trigger("becameVisible"),this.forEachChildView(function(e){var t=N(e,"isVisible");(t||null===t)&&e._notifyBecameVisible()})},_notifyBecameHidden:function(){this.trigger("becameHidden"),this.forEachChildView(function(e){var t=N(e,"isVisible");(t||null===t)&&e._notifyBecameHidden()})},_isAncestorHidden:function(){for(var e=N(this,"parentView");e;){if(N(e,"isVisible")===!1)return!0;e=N(e,"parentView")}return!1},transitionTo:function(e,t){this._transitionTo(e,t)},_transitionTo:function(e){var t=this.currentState,r=this.currentState=this._states[e];this._state=e,t&&t.exit&&t.exit(this),r.enter&&r.enter(this)},handleEvent:function(e,t){return this.currentState.handleEvent(this,e,t)},registerObserver:function(e,t,r,n){if(n||"function"!=typeof r||(n=r,r=null),e&&"object"==typeof e){var i=this,a=function(){i.currentState.invokeObserver(this,n)},s=function(){I.scheduleOnce("render",this,a)};k(e,t,r,s),this.one("willClearRender",function(){D(e,t,r,s)})}}});M(it.prototype,"state","_state"),M(it.prototype,"states","_states"),it.reopenClass({_parsePropertyPath:function(e){var t,r,n=e.split(":"),i=n[0],a="";return n.length>1&&(t=n[1],3===n.length&&(r=n[2]),a=":"+t,r&&(a+=":"+r)),{path:i,classNames:a,className:""===t?void 0:t,falsyClassName:r}},_classStringForValue:function(e,t,r,n){if(q(t)&&(t=0!==N(t,"length")),r||n)return r&&t?r:n&&!t?n:null;if(t===!0){var i=e.split(".");return K(i[i.length-1])}return t!==!1&&null!=t?t:null}});var at=A.extend(P).create();it.addMutationListener=function(e){at.on("change",e)},it.removeMutationListener=function(e){at.off("change",e)},it.notifyMutationListeners=function(){at.trigger("change")},it.views={},it.childViewsProperty=rt,it.applyAttributeBindings=function(e,t,r){var n=z(r);"value"===t||"string"!==n&&("number"!==n||isNaN(r))?"value"===t||"boolean"===n?F(r)||r===!1?(e.removeAttr(t),"required"===t?e.removeProp(t):e.prop(t,"")):r!==e.prop(t)&&e.prop(t,r):r||e.removeAttr(t):r!==e.attr(t)&&e.attr(t,r)},O["default"]=it}),e("ember",["ember-metal","ember-runtime","ember-handlebars","ember-views","ember-routing","ember-routing-handlebars","ember-application","ember-extension-support"],function(){"use strict";i.__loader.registry["ember-testing"]&&t("ember-testing")}),e("morph",["./morph/morph","./morph/dom-helper","exports"],function(e,t,r){"use strict";var n,n=e["default"];r.Morph=n;var i,i=t["default"];r.DOMHelper=i}),e("morph/dom-helper",["../morph/morph","./dom-helper/build-html-dom","exports"],function(e,t,r){"use strict";function n(e){return e===c}function i(e){return e&&e.namespaceURI===c&&!h[e.tagName]?c:null}function a(e,t){if("TABLE"===t.tagName){var r=f.exec(e);if(r){var n=r[1];return"tr"===n||"col"===n}}}function s(e,t){var r=t.document.createElement("div");return r.innerHTML=""+e+"",r.firstChild.childNodes}function o(e){this.document=e||window.document,this.namespace=null}var u=e["default"],l=t.buildHTMLDOM,c=t.svgNamespace,h=t.svgHTMLIntegrationPoints,p=function(){var e=document.createElement("div");e.appendChild(document.createTextNode(""));var t=e.cloneNode(!0);return 0===t.childNodes.length}(),m=function(){var e=document.createElement("input");e.setAttribute("checked","checked");var t=e.cloneNode(!1);return!t.checked}(),f=/<([\w:]+)/,d=o.prototype;d.constructor=o,d.insertBefore=function(e,t,r){return e.insertBefore(t,r)},d.appendChild=function(e,t){return e.appendChild(t)},d.appendText=function(e,t){return e.appendChild(this.document.createTextNode(t))},d.setAttribute=function(e,t,r){e.setAttribute(t,r)},d.createElement=document.createElementNS?function(e,t){var r=this.namespace;return t&&(r="svg"===e?c:i(t)),r?this.document.createElementNS(r,e):this.document.createElement(e)}:function(e){return this.document.createElement(e)},d.setNamespace=function(e){this.namespace=e},d.detectNamespace=function(e){this.namespace=i(e)},d.createDocumentFragment=function(){return this.document.createDocumentFragment()},d.createTextNode=function(e){return this.document.createTextNode(e)},d.repairClonedNode=function(e,t,r){if(p&&t.length>0)for(var n=0,i=t.length;i>n;n++){var a=this.document.createTextNode(""),s=t[n],o=e.childNodes[s];o?e.insertBefore(a,o):e.appendChild(a)}m&&r&&e.setAttribute("checked","checked")},d.cloneNode=function(e,t){var r=e.cloneNode(!!t);return r},d.createMorph=function(e,t,r,n){return n||1!==e.nodeType||(n=e),new u(e,t,r,this,n)},d.createMorphAt=function(e,t,r,n){var i=e.childNodes,a=-1===t?null:i[t],s=-1===r?null:i[r];return this.createMorph(e,a,s,n)},d.insertMorphBefore=function(e,t,r){var n=this.document.createTextNode(""),i=this.document.createTextNode("");return e.insertBefore(n,t),e.insertBefore(i,t),this.createMorph(e,n,i,r)},d.appendMorph=function(e,t){var r=this.document.createTextNode(""),n=this.document.createTextNode("");return e.appendChild(r),e.appendChild(n),this.createMorph(e,r,n,t)},d.parseHTML=function(e,t){var r=n(this.namespace)&&!h[t.tagName];if(r)return s(e,this);var i=l(e,t,this);if(a(e,t)){for(var o=i[0];o&&1!==o.nodeType;)o=o.nextSibling;return o.childNodes}return i},r["default"]=o}),e("morph/dom-helper/build-html-dom",["exports"],function(e){"use strict";function t(e,t){t="­"+t,e.innerHTML=t;for(var r=e.childNodes,n=r[0];1===n.nodeType&&!n.nodeName;)n=n.firstChild;if(3===n.nodeType&&"­"===n.nodeValue.charAt(0)){var i=n.nodeValue.slice(1);i.length?n.nodeValue=n.nodeValue.slice(1):n.parentNode.removeChild(n)}return r}function r(e,r){var n=r.tagName,i=r.outerHTML||(new XMLSerializer).serializeToString(r);if(!i)throw"Can't set innerHTML on "+n+" in this browser";for(var s=a[n.toLowerCase()],o=i.match(new RegExp("<"+n+"([^>]*)>","i"))[0],u="",l=[o,e,u],c=s.length,h=1+c;c--;)l.unshift("<"+s[c]+">"),l.push("");var p=document.createElement("div");t(p,l.join(""));for(var m=p;h--;)for(m=m.firstChild;m&&1!==m.nodeType;)m=m.nextSibling;for(;m&&m.tagName!==n;)m=m.nextSibling;return m?m.childNodes:[]}var n={foreignObject:1,desc:1,title:1};e.svgHTMLIntegrationPoints=n;var i="http://www.w3.org/2000/svg";e.svgNamespace=i;var a,s,o=document.createElementNS&&function(){var e=document.createElementNS(i,"title");return e.innerHTML="
    ",0===e.childNodes.length||1!==e.childNodes[0].nodeType}(),u=function(){var e=document.createElement("div");return e.innerHTML="
    ",e.firstChild.innerHTML="",""===e.firstChild.innerHTML}(),l=document&&function(){var e=document.createElement("div");return e.innerHTML="Test: Value","Test:"===e.childNodes[0].nodeValue&&" Value"===e.childNodes[2].nodeValue}(),c=document.createElement("table");try{c.innerHTML="
    "}catch(h){}finally{s=0===c.childNodes.length}s&&(a={colgroup:["table"],table:[],tbody:["table"],tfoot:["table"],thead:["table"],tr:["table","tbody"]});var p=document.createElement("select");p.innerHTML="",p&&(a=a||{},a.select=[]);var m;m=u?function(e,r,n){return r=n.cloneNode(r,!1),t(r,e),r.childNodes}:function(e,t,r){return t=r.cloneNode(t,!1),t.innerHTML=e,t.childNodes};var f;f=a||l?function(e,t,n){var i=[],s=[];e=e.replace(/(\s*)()(\s*)/g,function(e,t,r){return s.push(r),t});var o;o=a[t.tagName.toLowerCase()]?r(e,t):m(e,t,n);var u,l,c,h,p=[];for(u=0;c=o[u];u++)if(1===c.nodeType)if("SCRIPT"===c.tagName)p.push(c);else for(h=c.getElementsByTagName("script"),l=0;l0&&(d=n.document.createTextNode(v),f.parentNode.insertBefore(d,f)),b=s[u],b&&b.length>0&&(d=n.document.createTextNode(b),f.parentNode.insertBefore(d,f.nextSibling));return o}:m;var d;d=o?function(e,t,r){return n[t.tagName]?f(e,document.createElement("div"),r):f(e,t,r)}:f,e.buildHTMLDOM=d}),e("morph/morph",["exports"],function(e){"use strict";function t(e,t){if(null===e||null===t)throw new Error("a fragment parent must have boundary nodes in order to detect insertion")}function r(e){if(!e||1!==e.nodeType)throw new Error("An element node must be provided for a contextualElement, you provided "+(e?"nodeType "+e.nodeType:"nothing"))}function n(e,n,i,a,s){11===e.nodeType?(t(n,i),this.element=null):this.element=e,this._parent=e,this.start=n,this.end=i,this.domHelper=a,r(s),this.contextualElement=s,this.reset()}function i(e,t,r){for(var n,i=t,a=r.length;a--;)n=r[a],e.insertBefore(n,i),i=n}function a(e,t,r){var n,i;for(n=null===r?e.lastChild:r.previousSibling;null!==n&&n!==t;)i=n.previousSibling,e.removeChild(n),n=i}var s=Array.prototype.splice;n.prototype.reset=function(){this.text=null,this.owner=null,this.morphs=null,this.before=null,this.after=null,this.escaped=!0},n.prototype.parent=function(){if(!this.element){var e=this.start.parentNode;this._parent!==e&&(this.element=this._parent=e)}return this._parent},n.prototype.destroy=function(){this.owner?this.owner.removeMorph(this):a(this.element||this.parent(),this.start,this.end)},n.prototype.removeMorph=function(e){for(var t=this.morphs,r=0,n=t.length;n>r;r++)if(t[r]===e){this.replace(r,1);break}},n.prototype.update=function(e){this._update(this.element||this.parent(),e)},n.prototype.updateNode=function(e){var t=this.element||this.parent();return e?void this._updateNode(t,e):this._updateText(t,"")},n.prototype.updateText=function(e){this._updateText(this.element||this.parent(),e)},n.prototype.updateHTML=function(e){var t=this.element||this.parent();return e?void this._updateHTML(t,e):this._updateText(t,"")},n.prototype._update=function(e,t){null===t||void 0===t?this._updateText(e,""):"string"==typeof t?this.escaped?this._updateText(e,t):this._updateHTML(e,t):t.nodeType?this._updateNode(e,t):t.string?this._updateHTML(e,t.string):this._updateText(e,t.toString())},n.prototype._updateNode=function(e,t){if(this.text){if(3===t.nodeType)return void(this.text.nodeValue=t.nodeValue);this.text=null}var r=this.start,n=this.end;a(e,r,n),e.insertBefore(t,n),null!==this.before&&(this.before.end=r.nextSibling),null!==this.after&&(this.after.start=n.previousSibling)},n.prototype._updateText=function(e,t){if(this.text)return void(this.text.nodeValue=t);var r=this.domHelper.createTextNode(t);this.text=r,a(e,this.start,this.end),e.insertBefore(r,this.end),null!==this.before&&(this.before.end=r),null!==this.after&&(this.after.start=r)},n.prototype._updateHTML=function(e,t){var r=this.start,n=this.end;a(e,r,n),this.text=null;var s=this.domHelper.parseHTML(t,this.contextualElement);i(e,n,s),null!==this.before&&(this.before.end=r.nextSibling),null!==this.after&&(this.after.start=n.previousSibling)},n.prototype.append=function(e){null===this.morphs&&(this.morphs=[]);var t=this.morphs.length;return this.insert(t,e)},n.prototype.insert=function(e,t){null===this.morphs&&(this.morphs=[]);var r=this.element||this.parent(),i=this.morphs,a=e>0?i[e-1]:null,s=e0?c[e-1]:null,p=e+t0&&a(l,m,f),0===d)return null!==h&&(h.after=p,h.end=f),null!==p&&(p.before=h,p.start=m),void c.splice(e,t);if(i=new Array(d+2),d>0){for(o=0;d>o;o++)i[o+2]=u=new n(l,m,f,this.domHelper,this.contextualElement),u._update(l,r[o]),u.owner=this,null!==h&&(u.before=h,h.end=m.nextSibling,h.after=u),h=u,m=null===f?l.lastChild:f.previousSibling;null!==p&&(u.after=p,p.before=u,p.start=f.previousSibling)}i[0]=e,i[1]=t,s.apply(c,i)},e["default"]=n}),e("route-recognizer",["route-recognizer/dsl","exports"],function(e,t){"use strict";function r(e){return"[object Array]"===Object.prototype.toString.call(e)}function n(e){this.string=e}function i(e){this.name=e}function a(e){this.name=e}function s(){}function o(e,t,r){"/"===e.charAt(0)&&(e=e.substr(1));for(var o=e.split("/"),u=[],l=0,c=o.length;c>l;l++){var h,p=o[l];(h=p.match(/^:([^\/]+)$/))?(u.push(new i(h[1])),t.push(h[1]),r.dynamics++):(h=p.match(/^\*([^\/]+)$/))?(u.push(new a(h[1])),t.push(h[1]),r.stars++):""===p?u.push(new s):(u.push(new n(p)),r.statics++)}return u}function u(e){this.charSpec=e,this.nextStates=[]}function l(e){return e.sort(function(e,t){if(e.types.stars!==t.types.stars)return e.types.stars-t.types.stars;if(e.types.stars){if(e.types.statics!==t.types.statics)return t.types.statics-e.types.statics;if(e.types.dynamics!==t.types.dynamics)return t.types.dynamics-e.types.dynamics}return e.types.dynamics!==t.types.dynamics?e.types.dynamics-t.types.dynamics:e.types.statics!==t.types.statics?t.types.statics-e.types.statics:0})}function c(e,t){for(var r=[],n=0,i=e.length;i>n;n++){var a=e[n];r=r.concat(a.match(t))}return r}function h(e){this.queryParams=e||{}}function p(e,t,r){for(var n=e.handlers,i=e.regex,a=t.match(i),s=1,o=new h(r),u=0,l=n.length;l>u;u++){for(var c=n[u],p=c.names,m={},f=0,d=p.length;d>f;f++)m[p[f]]=a[s++];o.push({handler:c.handler,params:m,isDynamic:!!p.length})}return o}function m(e,t){return t.eachChar(function(t){e=e.put(t)}),e}var f=e["default"],d=["/",".","*","+","?","|","(",")","[","]","{","}","\\"],v=new RegExp("(\\"+d.join("|\\")+")","g");n.prototype={eachChar:function(e){for(var t,r=this.string,n=0,i=r.length;i>n;n++)t=r.charAt(n),e({validChars:t})},regex:function(){return this.string.replace(v,"\\$1")},generate:function(){return this.string}},i.prototype={eachChar:function(e){e({invalidChars:"/",repeat:!0})},regex:function(){return"([^/]+)"},generate:function(e){return e[this.name]}},a.prototype={eachChar:function(e){e({invalidChars:"",repeat:!0})},regex:function(){return"(.+)"},generate:function(e){return e[this.name]}},s.prototype={eachChar:function(){},regex:function(){return""},generate:function(){return""}},u.prototype={get:function(e){for(var t=this.nextStates,r=0,n=t.length;n>r;r++){var i=t[r],a=i.charSpec.validChars===e.validChars;if(a=a&&i.charSpec.invalidChars===e.invalidChars)return i}},put:function(e){var t;return(t=this.get(e))?t:(t=new u(e),this.nextStates.push(t),e.repeat&&t.nextStates.push(t),t)},match:function(e){for(var t,r,n,i=this.nextStates,a=[],s=0,o=i.length;o>s;s++)t=i[s],r=t.charSpec,"undefined"!=typeof(n=r.validChars)?-1!==n.indexOf(e)&&a.push(t):"undefined"!=typeof(n=r.invalidChars)&&-1===n.indexOf(e)&&a.push(t);return a}};var b=Object.create||function(e){function t(){}return t.prototype=e,new t};h.prototype=b({splice:Array.prototype.splice,slice:Array.prototype.slice,push:Array.prototype.push,length:0,queryParams:null});var y=function(){this.rootState=new u,this.names={}};y.prototype={add:function(e,t){for(var r,n=this.rootState,i="^",a={statics:0,dynamics:0,stars:0},u=[],l=[],c=!0,h=0,p=e.length;p>h;h++){var f=e[h],d=[],v=o(f.path,d,a);l=l.concat(v);for(var b=0,y=v.length;y>b;b++){var g=v[b];g instanceof s||(c=!1,n=n.put({validChars:"/"}),i+="/",n=m(n,g),i+=g.regex())}var _={handler:f.handler,names:d};u.push(_)}c&&(n=n.put({validChars:"/"}),i+="/"),n.handlers=u,n.regex=new RegExp(i+"$"),n.types=a,(r=t&&t.as)&&(this.names[r]={segments:l,handlers:u})},handlersFor:function(e){var t=this.names[e],r=[];if(!t)throw new Error("There is no route named "+e);for(var n=0,i=t.handlers.length;i>n;n++)r.push(t.handlers[n]);return r},hasRoute:function(e){return!!this.names[e]},generate:function(e,t){var r=this.names[e],n="";if(!r)throw new Error("There is no route named "+e);for(var i=r.segments,a=0,o=i.length;o>a;a++){var u=i[a];u instanceof s||(n+="/",n+=u.generate(t))}return"/"!==n.charAt(0)&&(n="/"+n),t&&t.queryParams&&(n+=this.generateQueryString(t.queryParams,r.handlers)),n},generateQueryString:function(e){var t=[],n=[];for(var i in e)e.hasOwnProperty(i)&&n.push(i);n.sort();for(var a=0,s=n.length;s>a;a++){i=n[a];var o=e[i];if(null!=o){var u=encodeURIComponent(i);if(r(o))for(var l=0,c=o.length;c>l;l++){var h=i+"[]="+encodeURIComponent(o[l]);t.push(h)}else u+="="+encodeURIComponent(o),t.push(u)}}return 0===t.length?"":"?"+t.join("&")},parseQueryString:function(e){for(var t=e.split("&"),r={},n=0;n2&&"[]"===s.slice(o-2)&&(u=!0,s=s.slice(0,o-2),r[s]||(r[s]=[])),i=a[1]?decodeURIComponent(a[1]):""),u?r[s].push(i):r[s]=i}return r},recognize:function(e){var t,r,n,i,a=[this.rootState],s={},o=!1;if(i=e.indexOf("?"),-1!==i){var u=e.substr(i+1,e.length);e=e.substr(0,i),s=this.parseQueryString(u)}for(e=decodeURI(e),"/"!==e.charAt(0)&&(e="/"+e),t=e.length,t>1&&"/"===e.charAt(t-1)&&(e=e.substr(0,t-1),o=!0),r=0,n=e.length;n>r&&(a=c(a,e.charAt(r)),a.length);r++);var h=[];for(r=0,n=a.length;n>r;r++)a[r].handlers&&h.push(a[r]);a=l(h);var m=h[0];return m&&m.handlers?(o&&"(.+)$"===m.regex.source.slice(-5)&&(e+="/"),p(m,e,s)):void 0}},y.prototype.map=f,t["default"]=y}),e("route-recognizer/dsl",["exports"],function(e){"use strict";function t(e,t,r){this.path=e,this.matcher=t,this.delegate=r}function r(e){this.routes={},this.children={},this.target=e}function n(e,r,i){return function(a,s){var o=e+a;return s?void s(n(o,r,i)):new t(e+a,r,i)}}function i(e,t,r){for(var n=0,i=0,a=e.length;a>i;i++)n+=e[i].path.length;t=t.substr(n);var s={path:t,handler:r};e.push(s)}function a(e,t,r,n){var s=t.routes;for(var o in s)if(s.hasOwnProperty(o)){var u=e.slice();i(u,o,s[o]),t.children[o]?a(u,t.children[o],r,n):r.call(n,u)}}t.prototype={to:function(e,t){var r=this.delegate;if(r&&r.willAddRoute&&(e=r.willAddRoute(this.matcher.target,e)),this.matcher.add(this.path,e),t){if(0===t.length)throw new Error("You must have an argument in the function passed to `to`");this.matcher.addChild(this.path,e,t,this.delegate)}return this}},r.prototype={add:function(e,t){this.routes[e]=t},addChild:function(e,t,i,a){var s=new r(t);this.children[e]=s;var o=n(e,s,a);a&&a.contextEntered&&a.contextEntered(t,o),i(o)}},e["default"]=function(e,t){var i=new r;e(n("",i,this.delegate)),a([],i,function(e){t?t(this,e):this.add(e)},this)}}),e("router",["./router/router","exports"],function(e,t){"use strict";var r=e["default"];t["default"]=r}),e("router/handler-info",["./utils","rsvp/promise","exports"],function(e,t,r){"use strict";function n(e){var t=e||{};s(this,t),this.initialize(t)}function i(e,t){if(!e^!t)return!1;if(!e)return!0;for(var r in e)if(e.hasOwnProperty(r)&&e[r]!==t[r])return!1;return!0}var a=e.bind,s=e.merge,o=(e.serialize,e.promiseLabel),u=e.applyHook,l=t["default"];n.prototype={name:null,handler:null,params:null,context:null,factory:null,initialize:function(){},log:function(e,t){e.log&&e.log(this.name+": "+t)},promiseLabel:function(e){return o("'"+this.name+"' "+e)},getUnresolved:function(){return this},serialize:function(){return this.params||{}},resolve:function(e,t){var r=a(this,this.checkForAbort,e),n=a(this,this.runBeforeModelHook,t),i=a(this,this.getModel,t),s=a(this,this.runAfterModelHook,t),o=a(this,this.becomeResolved,t);return l.resolve(void 0,this.promiseLabel("Start handler")).then(r,null,this.promiseLabel("Check for abort")).then(n,null,this.promiseLabel("Before model")).then(r,null,this.promiseLabel("Check if aborted during 'beforeModel' hook")).then(i,null,this.promiseLabel("Model")).then(r,null,this.promiseLabel("Check if aborted in 'model' hook")).then(s,null,this.promiseLabel("After model")).then(r,null,this.promiseLabel("Check if aborted in 'afterModel' hook")).then(o,null,this.promiseLabel("Become resolved"))},runBeforeModelHook:function(e){return e.trigger&&e.trigger(!0,"willResolveModel",e,this.handler),this.runSharedModelHook(e,"beforeModel",[])},runAfterModelHook:function(e,t){var r=this.name;return this.stashResolvedModel(e,t),this.runSharedModelHook(e,"afterModel",[t]).then(function(){return e.resolvedModels[r]},null,this.promiseLabel("Ignore fulfillment value and return model value"))},runSharedModelHook:function(e,t,r){this.log(e,"calling "+t+" hook"),this.queryParams&&r.push(this.queryParams),r.push(e);var n=u(this.handler,t,r);return n&&n.isTransition&&(n=null),l.resolve(n,this.promiseLabel("Resolve value returned from one of the model hooks"))},getModel:null,checkForAbort:function(e,t){return l.resolve(e(),this.promiseLabel("Check for abort")).then(function(){return t},null,this.promiseLabel("Ignore fulfillment value and continue"))},stashResolvedModel:function(e,t){e.resolvedModels=e.resolvedModels||{},e.resolvedModels[this.name]=t},becomeResolved:function(e,t){var r=this.serialize(t);return e&&(this.stashResolvedModel(e,t),e.params=e.params||{},e.params[this.name]=r),this.factory("resolved",{context:t,name:this.name,handler:this.handler,params:r})},shouldSupercede:function(e){if(!e)return!0;var t=e.context===this.context;return e.name!==this.name||this.hasOwnProperty("context")&&!t||this.hasOwnProperty("params")&&!i(this.params,e.params)}},r["default"]=n}),e("router/handler-info/factory",["router/handler-info/resolved-handler-info","router/handler-info/unresolved-handler-info-by-object","router/handler-info/unresolved-handler-info-by-param","exports"],function(e,t,r,n){"use strict";function i(e,t){var r=i.klasses[e],n=new r(t||{});return n.factory=i,n}var a=e["default"],s=t["default"],o=r["default"];i.klasses={resolved:a,param:o,object:s},n["default"]=i}),e("router/handler-info/resolved-handler-info",["../handler-info","router/utils","rsvp/promise","exports"],function(e,t,r,n){"use strict";var i=e["default"],a=t.subclass,s=(t.promiseLabel,r["default"]),o=a(i,{resolve:function(e,t){return t&&t.resolvedModels&&(t.resolvedModels[this.name]=this.context),s.resolve(this,this.promiseLabel("Resolve"))},getUnresolved:function(){return this.factory("param",{name:this.name,handler:this.handler,params:this.params})},isResolved:!0});n["default"]=o}),e("router/handler-info/unresolved-handler-info-by-object",["../handler-info","router/utils","rsvp/promise","exports"],function(e,t,r,n){"use strict";var i=e["default"],a=(t.merge,t.subclass),s=(t.promiseLabel,t.isParam),o=r["default"],u=a(i,{getModel:function(e){return this.log(e,this.name+": resolving provided model"),o.resolve(this.context)},initialize:function(e){this.names=e.names||[],this.context=e.context},serialize:function(e){var t=e||this.context,r=this.names,n=this.handler,i={};if(s(t))return i[r[0]]=t,i;if(n.serialize)return n.serialize(t,r);if(1===r.length){var a=r[0];return i[a]=/_id$/.test(a)?t.id:t,i}}});n["default"]=u}),e("router/handler-info/unresolved-handler-info-by-param",["../handler-info","router/utils","exports"],function(e,t,r){"use strict";var n=e["default"],i=t.resolveHook,a=t.merge,s=t.subclass,o=(t.promiseLabel,s(n,{initialize:function(e){this.params=e.params||{}},getModel:function(e){var t=this.params;e&&e.queryParams&&(t={},a(t,this.params),t.queryParams=e.queryParams);var r=this.handler,n=i(r,"deserialize")||i(r,"model");return this.runSharedModelHook(e,n,[t])}}));r["default"]=o}),e("router/router",["route-recognizer","rsvp/promise","./utils","./transition-state","./transition","./transition-intent/named-transition-intent","./transition-intent/url-transition-intent","./handler-info","exports"],function(e,t,r,n,i,a,s,o,u){"use strict";function l(){this.recognizer=new w,this.reset()}function c(e,t){var r,n=!!this.activeTransition,i=n?this.activeTransition.state:this.state,a=e.applyToState(i,this.recognizer,this.getHandler,t),s=N(i.queryParams,a.queryParams);return y(a.handlerInfos,i.handlerInfos)?s&&(r=this.queryParamsTransition(s,n,i,a))?r:new D(this):t?void p(this,a):(r=new D(this,e,a),this.activeTransition&&this.activeTransition.abort(),this.activeTransition=r,r.promise=r.promise.then(function(e){return v(r,e.state)},null,S("Settle transition promise when transition is finalized")),n||_(this,a,r),h(this,a,s),r)}function h(e,t,r){r&&(e._changedQueryParams=r.all,C(e,t.handlerInfos,!0,["queryParamsDidChange",r.changed,r.all,r.removed]),e._changedQueryParams=null)}function p(e,t,r){var n=f(e.state,t);P(n.exited,function(e){var t=e.handler;delete t.context,V(t,"reset",!0,r),V(t,"exit",r)});var i=e.oldState=e.state;e.state=t;var a=e.currentHandlerInfos=n.unchanged.slice();try{P(n.reset,function(e){var t=e.handler;V(t,"reset",!1,r)}),P(n.updatedContext,function(e){return m(a,e,!1,r)}),P(n.entered,function(e){return m(a,e,!0,r) +})}catch(s){throw e.state=i,e.currentHandlerInfos=i.handlerInfos,s}e.state.queryParams=g(e,a,t.queryParams,r)}function m(e,t,r,n){var i=t.handler,a=t.context;if(r&&V(i,"enter",n),n&&n.isAborted)throw new j;if(i.context=a,V(i,"contextDidChange"),V(i,"setup",a,n),n&&n.isAborted)throw new j;return e.push(t),!0}function f(e,t){var r,n,i,a=e.handlerInfos,s=t.handlerInfos,o={updatedContext:[],exited:[],entered:[],unchanged:[]},u=!1;for(n=0,i=s.length;i>n;n++){var l=a[n],c=s[n];l&&l.handler===c.handler||(r=!0),r?(o.entered.push(c),l&&o.exited.unshift(l)):u||l.context!==c.context?(u=!0,o.updatedContext.push(c)):o.unchanged.push(l)}for(n=s.length,i=a.length;i>n;n++)o.exited.unshift(a[n]);return o.reset=o.updatedContext.slice(),o.reset.reverse(),o}function d(e,t){var r=e.urlMethod;if(r){for(var n=e.router,i=t.handlerInfos,a=i[i.length-1].name,s={},o=i.length-1;o>=0;--o){var u=i[o];A(s,u.params),u.handler.inaccessibleByURL&&(r=null)}if(r){s.queryParams=e._visibleQueryParams||t.queryParams;var l=n.recognizer.generate(a,s);"replace"===r?n.replaceURL(l):n.updateURL(l)}}}function v(e,t){try{O(e.router,e.sequence,"Resolved all models on destination route; finalizing transition.");{var r=e.router,n=t.handlerInfos;e.sequence}return p(r,t,e),e.isAborted?(r.state.handlerInfos=r.currentHandlerInfos,x.reject(k(e))):(d(e,t,e.intent.url),e.isActive=!1,r.activeTransition=null,C(r,r.currentHandlerInfos,!0,["didTransition"]),r.didTransition&&r.didTransition(r.currentHandlerInfos),O(r,e.sequence,"TRANSITION COMPLETE."),n[n.length-1].handler)}catch(i){if(!(i instanceof j)){var a=e.state.handlerInfos;e.trigger(!0,"error",i,e,a[a.length-1].handler),e.abort()}throw i}}function b(e,t,r){var n=t[0]||"/",i=t[t.length-1],a={};i&&i.hasOwnProperty("queryParams")&&(a=L.call(t).queryParams);var s;if(0===t.length){O(e,"Updating query params");var o=e.state.handlerInfos;s=new M({name:o[o.length-1].name,contexts:[],queryParams:a})}else"/"===n.charAt(0)?(O(e,"Attempting URL transition to "+n),s=new R({url:n})):(O(e,"Attempting transition to "+n),s=new M({name:t[0],contexts:E.call(t,1),queryParams:a}));return e.transitionByIntent(s,r)}function y(e,t){if(e.length!==t.length)return!1;for(var r=0,n=e.length;n>r;++r)if(e[r]!==t[r])return!1;return!0}function g(e,t,r,n){for(var i in r)r.hasOwnProperty(i)&&null===r[i]&&delete r[i];var a=[];C(e,t,!0,["finalizeQueryParamChange",r,a,n]),n&&(n._visibleQueryParams={});for(var s={},o=0,u=a.length;u>o;++o){var l=a[o];s[l.key]=l.value,n&&l.visible!==!1&&(n._visibleQueryParams[l.key]=l.value)}return s}function _(e,t,r){var n,i,a,s,o,u,l=e.state.handlerInfos,c=[],h=null;for(s=l.length,a=0;s>a;a++){if(o=l[a],u=t.handlerInfos[a],!u||o.name!==u.name){h=a;break}u.isResolved||c.push(o)}null!==h&&(n=l.slice(h,s),i=function(e){for(var t=0,r=n.length;r>t;t++)if(n[t].name===e)return!0;return!1},e._triggerWillLeave(n,r,i)),c.length>0&&e._triggerWillChangeContext(c,r),C(e,l,!0,["willTransition",r])}var w=e["default"],x=t["default"],C=r.trigger,O=r.log,E=r.slice,P=r.forEach,A=r.merge,T=(r.serialize,r.extractQueryParams),N=r.getChangelist,S=r.promiseLabel,V=r.callHook,I=n["default"],k=i.logAbort,D=i.Transition,j=i.TransitionAborted,M=a["default"],R=s["default"],L=(o.ResolvedHandlerInfo,Array.prototype.pop);l.prototype={map:function(e){this.recognizer.delegate=this.delegate,this.recognizer.map(e,function(e,t){for(var r=t.length-1,n=!0;r>=0&&n;--r){var i=t[r];e.add(t,{as:i.handler}),n="/"===i.path||""===i.path||".index"===i.handler.slice(-6)}})},hasRoute:function(e){return this.recognizer.hasRoute(e)},queryParamsTransition:function(e,t,r,n){var i=this;if(h(this,n,e),!t&&this.activeTransition)return this.activeTransition;var a=new D(this);return a.queryParamsOnly=!0,r.queryParams=g(this,n.handlerInfos,n.queryParams,a),a.promise=a.promise.then(function(e){return d(a,r,!0),i.didTransition&&i.didTransition(i.currentHandlerInfos),e},null,S("Transition complete")),a},transitionByIntent:function(e){try{return c.apply(this,arguments)}catch(t){return new D(this,e,null,t)}},reset:function(){this.state&&P(this.state.handlerInfos.slice().reverse(),function(e){var t=e.handler;V(t,"exit")}),this.state=new I,this.currentHandlerInfos=null},activeTransition:null,handleURL:function(e){var t=E.call(arguments);return"/"!==e.charAt(0)&&(t[0]="/"+e),b(this,t).method(null)},updateURL:function(){throw new Error("updateURL is not implemented")},replaceURL:function(e){this.updateURL(e)},transitionTo:function(){return b(this,arguments)},intermediateTransitionTo:function(){return b(this,arguments,!0)},refresh:function(e){for(var t=this.activeTransition?this.activeTransition.state:this.state,r=t.handlerInfos,n={},i=0,a=r.length;a>i;++i){var s=r[i];n[s.name]=s.params||{}}O(this,"Starting a refresh transition");var o=new M({name:r[r.length-1].name,pivotHandler:e||r[0].handler,contexts:[],queryParams:this._changedQueryParams||t.queryParams||{}});return this.transitionByIntent(o,!1)},replaceWith:function(){return b(this,arguments).method("replace")},generate:function(e){for(var t=T(E.call(arguments,1)),r=t[0],n=t[1],i=new M({name:e,contexts:r}),a=i.applyToState(this.state,this.recognizer,this.getHandler),s={},o=0,u=a.handlerInfos.length;u>o;++o){var l=a.handlerInfos[o],c=l.serialize();A(s,c)}return s.queryParams=n,this.recognizer.generate(e,s)},applyIntent:function(e,t){var r=new M({name:e,contexts:t}),n=this.activeTransition&&this.activeTransition.state||this.state;return r.applyToState(n,this.recognizer,this.getHandler)},isActiveIntent:function(e,t,r){var n,i,a=this.state.handlerInfos;if(!a.length)return!1;var s=a[a.length-1].name,o=this.recognizer.handlersFor(s),u=0;for(i=o.length;i>u&&(n=a[u],n.name!==e);++u);if(u===o.length)return!1;var l=new I;l.handlerInfos=a.slice(0,u+1),o=o.slice(0,u+1);var c=new M({name:s,contexts:t}),h=c.applyToHandlers(l,o,this.getHandler,s,!0,!0),p=y(h.handlerInfos,l.handlerInfos);if(!r||!p)return p;var m={};A(m,r);var f=this.state.queryParams;for(var d in f)f.hasOwnProperty(d)&&m.hasOwnProperty(d)&&(m[d]=f[d]);return p&&!N(m,r)},isActive:function(e){var t=T(E.call(arguments,1));return this.isActiveIntent(e,t[0],t[1])},trigger:function(){var e=E.call(arguments);C(this,this.currentHandlerInfos,!1,e)},log:null,_willChangeContextEvent:"willChangeContext",_triggerWillChangeContext:function(e,t){C(this,e,!0,[this._willChangeContextEvent,t])},_triggerWillLeave:function(e,t,r){C(this,e,!0,["willLeave",t,r])}},u["default"]=l}),e("router/transition-intent",["./utils","exports"],function(e,t){"use strict";function r(e){this.initialize(e),this.data=this.data||{}}e.merge;r.prototype={initialize:null,applyToState:null},t["default"]=r}),e("router/transition-intent/named-transition-intent",["../transition-intent","../transition-state","../handler-info/factory","../utils","exports"],function(e,t,r,n,i){"use strict";var a=e["default"],s=t["default"],o=r["default"],u=n.isParam,l=n.extractQueryParams,c=n.merge,h=n.subclass;i["default"]=h(a,{name:null,pivotHandler:null,contexts:null,queryParams:null,initialize:function(e){this.name=e.name,this.pivotHandler=e.pivotHandler,this.contexts=e.contexts||[],this.queryParams=e.queryParams},applyToState:function(e,t,r,n){var i=l([this.name].concat(this.contexts)),a=i[0],s=(i[1],t.handlersFor(a[0])),o=s[s.length-1].handler;return this.applyToHandlers(e,s,r,o,n)},applyToHandlers:function(e,t,r,n,i,a){var o,u,l=new s,h=this.contexts.slice(0),p=t.length;if(this.pivotHandler)for(o=0,u=t.length;u>o;++o)if(r(t[o].handler)===this.pivotHandler){p=o;break}!this.pivotHandler;for(o=t.length-1;o>=0;--o){var m=t[o],f=m.handler,d=r(f),v=e.handlerInfos[o],b=null;if(b=m.names.length>0?o>=p?this.createParamHandlerInfo(f,d,m.names,h,v):this.getHandlerInfoForDynamicSegment(f,d,m.names,h,v,n,o):this.createParamHandlerInfo(f,d,m.names,h,v),a){b=b.becomeResolved(null,b.context);var y=v&&v.context;m.names.length>0&&b.context===y&&(b.params=v&&v.params),b.context=y}var g=v;(o>=p||b.shouldSupercede(v))&&(p=Math.min(o,p),g=b),i&&!a&&(g=g.becomeResolved(null,g.context)),l.handlerInfos.unshift(g)}if(h.length>0)throw new Error("More context objects were passed than there are dynamic segments for the route: "+n);return i||this.invalidateChildren(l.handlerInfos,p),c(l.queryParams,this.queryParams||{}),l},invalidateChildren:function(e,t){for(var r=t,n=e.length;n>r;++r){{e[r]}e[r]=e[r].getUnresolved()}},getHandlerInfoForDynamicSegment:function(e,t,r,n,i,a,s){{var l;r.length}if(n.length>0){if(l=n[n.length-1],u(l))return this.createParamHandlerInfo(e,t,r,n,i);n.pop()}else{if(i&&i.name===e)return i;if(!this.preTransitionState)return i;var c=this.preTransitionState.handlerInfos[s];l=c&&c.context}return o("object",{name:e,handler:t,context:l,names:r})},createParamHandlerInfo:function(e,t,r,n,i){for(var a={},s=r.length;s--;){var l=i&&e===i.name&&i.params||{},c=n[n.length-1],h=r[s];if(u(c))a[h]=""+n.pop();else{if(!l.hasOwnProperty(h))throw new Error("You didn't provide enough string/numeric parameters to satisfy all of the dynamic segments for route "+e);a[h]=l[h]}}return o("param",{name:e,handler:t,params:a})}})}),e("router/transition-intent/url-transition-intent",["../transition-intent","../transition-state","../handler-info/factory","../utils","exports"],function(e,t,r,n,i){"use strict";function a(e){this.message=e||"UnrecognizedURLError",this.name="UnrecognizedURLError"}var s=e["default"],o=t["default"],u=r["default"],l=(n.oCreate,n.merge),c=n.subclass;i["default"]=c(s,{url:null,initialize:function(e){this.url=e.url},applyToState:function(e,t,r){var n,i,s=new o,c=t.recognize(this.url);if(!c)throw new a(this.url);var h=!1;for(n=0,i=c.length;i>n;++n){var p=c[n],m=p.handler,f=r(m);if(f.inaccessibleByURL)throw new a(this.url);var d=u("param",{name:m,handler:f,params:p.params}),v=e.handlerInfos[n];h||d.shouldSupercede(v)?(h=!0,s.handlerInfos[n]=d):s.handlerInfos[n]=v}return l(s.queryParams,c.queryParams),s}})}),e("router/transition-state",["./handler-info","./utils","rsvp/promise","exports"],function(e,t,r,n){"use strict";function i(){this.handlerInfos=[],this.queryParams={},this.params={}}var a=(e.ResolvedHandlerInfo,t.forEach),s=t.promiseLabel,o=t.callHook,u=r["default"];i.prototype={handlerInfos:null,queryParams:null,params:null,promiseLabel:function(e){var t="";return a(this.handlerInfos,function(e){""!==t&&(t+="."),t+=e.name}),s("'"+t+"': "+e)},resolve:function(e,t){function r(){return u.resolve(e(),c.promiseLabel("Check if should continue"))["catch"](function(e){return h=!0,u.reject(e)},c.promiseLabel("Handle abort"))}function n(e){var r=c.handlerInfos,n=t.resolveIndex>=r.length?r.length-1:t.resolveIndex;return u.reject({error:e,handlerWithError:c.handlerInfos[n].handler,wasAborted:h,state:c})}function i(e){var n=c.handlerInfos[t.resolveIndex].isResolved;if(c.handlerInfos[t.resolveIndex++]=e,!n){var i=e.handler;o(i,"redirect",e.context,t)}return r().then(s,null,c.promiseLabel("Resolve handler"))}function s(){if(t.resolveIndex===c.handlerInfos.length)return{error:null,state:c};var e=c.handlerInfos[t.resolveIndex];return e.resolve(r,t).then(i,null,c.promiseLabel("Proceed"))}var l=this.params;a(this.handlerInfos,function(e){l[e.name]=e.params||{}}),t=t||{},t.resolveIndex=0;var c=this,h=!1;return u.resolve(null,this.promiseLabel("Start transition")).then(s,null,this.promiseLabel("Resolve handler"))["catch"](n,this.promiseLabel("Handle error"))}},n["default"]=i}),e("router/transition",["rsvp/promise","./handler-info","./utils","exports"],function(e,t,r,n){"use strict";function i(e,t,r,n){function s(){return u.isAborted?o.reject(void 0,h("Transition aborted - reject")):void 0}var u=this;if(this.state=r||e.state,this.intent=t,this.router=e,this.data=this.intent&&this.intent.data||{},this.resolvedModels={},this.queryParams={},n)return void(this.promise=o.reject(n));if(r){this.params=r.params,this.queryParams=r.queryParams,this.handlerInfos=r.handlerInfos;var l=r.handlerInfos.length;l&&(this.targetName=r.handlerInfos[l-1].name);for(var c=0;l>c;++c){var p=r.handlerInfos[c];if(!p.isResolved)break;this.pivotHandler=p.handler}this.sequence=i.currentSequence++,this.promise=r.resolve(s,this)["catch"](function(e){return e.wasAborted||u.isAborted?o.reject(a(u)):(u.trigger("error",e.error,u,e.handlerWithError),u.abort(),o.reject(e.error))},h("Handle Abort"))}else this.promise=o.resolve(this.state),this.params={}}function a(e){return c(e.router,e.sequence,"detected abort."),new s}function s(e){this.message=e||"TransitionAborted",this.name="TransitionAborted"}var o=e["default"],u=(t.ResolvedHandlerInfo,r.trigger),l=r.slice,c=r.log,h=r.promiseLabel;i.currentSequence=0,i.prototype={targetName:null,urlMethod:"update",intent:null,params:null,pivotHandler:null,resolveIndex:0,handlerInfos:null,resolvedModels:null,isActive:!0,state:null,queryParamsOnly:!1,isTransition:!0,isExiting:function(e){for(var t=this.handlerInfos,r=0,n=t.length;n>r;++r){var i=t[r];if(i.name===e||i.handler===e)return!1}return!0},promise:null,data:null,then:function(e,t,r){return this.promise.then(e,t,r)},"catch":function(e,t){return this.promise["catch"](e,t)},"finally":function(e,t){return this.promise["finally"](e,t)},abort:function(){return this.isAborted?this:(c(this.router,this.sequence,this.targetName+": transition was aborted"),this.intent.preTransitionState=this.router.state,this.isAborted=!0,this.isActive=!1,this.router.activeTransition=null,this)},retry:function(){return this.abort(),this.router.transitionByIntent(this.intent,!1)},method:function(e){return this.urlMethod=e,this},trigger:function(e){var t=l.call(arguments);"boolean"==typeof e?t.shift():e=!1,u(this.router,this.state.handlerInfos.slice(0,this.resolveIndex+1),e,t)},followRedirects:function(){var e=this.router;return this.promise["catch"](function(t){return e.activeTransition?e.activeTransition.followRedirects():o.reject(t)})},toString:function(){return"Transition (sequence "+this.sequence+")"},log:function(e){c(this.router,this.sequence,e)}},i.prototype.send=i.prototype.trigger,n.Transition=i,n.logAbort=a,n.TransitionAborted=s}),e("router/utils",["exports"],function(e){"use strict";function t(e,t){for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r])}function r(e){var t,r,n=e&&e.length;return n&&n>0&&e[n-1]&&e[n-1].hasOwnProperty("queryParams")?(r=e[n-1].queryParams,t=v.call(e,0,n-1),[t,r]):[e,null]}function n(e){for(var t in e)if("number"==typeof e[t])e[t]=""+e[t];else if(b(e[t]))for(var r=0,n=e[t].length;n>r;r++)e[t][r]=""+e[t][r]}function i(e,t,r){e.log&&(3===arguments.length?e.log("Transition #"+t+": "+r):(r=t,e.log(r)))}function a(e,t){var r=arguments;return function(n){var i=v.call(r,2);return i.push(n),t.apply(e,i)}}function s(e){return"string"==typeof e||e instanceof String||"number"==typeof e||e instanceof Number}function o(e,t){for(var r=0,n=e.length;n>r&&!1!==t(e[r]);r++);}function u(e,t,r,n){if(e.triggerEvent)return void e.triggerEvent(t,r,n);var i=n.shift();if(!t){if(r)return;throw new Error("Could not trigger event '"+i+"'. There are no active handlers")}for(var a=!1,s=t.length-1;s>=0;s--){var o=t[s],u=o.handler;if(u.events&&u.events[i]){if(u.events[i].apply(u,n)!==!0)return;a=!0}}if(!a&&!r)throw new Error("Nothing handled the event '"+i+"'.")}function l(e,r){var i,a={all:{},changed:{},removed:{}};t(a.all,r);var s=!1;n(e),n(r);for(i in e)e.hasOwnProperty(i)&&(r.hasOwnProperty(i)||(s=!0,a.removed[i]=e[i]));for(i in r)if(r.hasOwnProperty(i))if(b(e[i])&&b(r[i]))if(e[i].length!==r[i].length)a.changed[i]=r[i],s=!0;else for(var o=0,u=e[i].length;u>o;o++)e[i][o]!==r[i][o]&&(a.changed[i]=r[i],s=!0);else e[i]!==r[i]&&(a.changed[i]=r[i],s=!0);return s&&a}function c(e){return"Router: "+e}function h(e,r){function n(t){e.call(this,t||{})}return n.prototype=y(e.prototype),t(n.prototype,r),n}function p(e,t){if(e){var r="_"+t;return e[r]&&r||e[t]&&t}}function m(e,t){var r=v.call(arguments,2);return f(e,t,r)}function f(e,t,r){var n=p(e,t);return n?e[n].apply(e,r):void 0}var d,v=Array.prototype.slice;d=Array.isArray?Array.isArray:function(e){return"[object Array]"===Object.prototype.toString.call(e)};var b=d;e.isArray=b;var y=Object.create||function(e){function t(){}return t.prototype=e,new t};e.oCreate=y,e.extractQueryParams=r,e.log=i,e.bind=a,e.forEach=o,e.trigger=u,e.getChangelist=l,e.promiseLabel=c,e.subclass=h,e.merge=t,e.slice=v,e.isParam=s,e.coerceQueryParamsToString=n,e.callHook=m,e.resolveHook=p,e.applyHook=f}),e("rsvp",["./rsvp/promise","./rsvp/events","./rsvp/node","./rsvp/all","./rsvp/all-settled","./rsvp/race","./rsvp/hash","./rsvp/hash-settled","./rsvp/rethrow","./rsvp/defer","./rsvp/config","./rsvp/map","./rsvp/resolve","./rsvp/reject","./rsvp/filter","./rsvp/asap","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m,f,d,v){"use strict";function b(e,t){S.async(e,t)}function y(){S.on.apply(S,arguments)}function g(){S.off.apply(S,arguments)}var _=e["default"],w=t["default"],x=r["default"],C=n["default"],O=i["default"],E=a["default"],P=s["default"],A=o["default"],T=u["default"],N=l["default"],S=c.config,V=c.configure,I=h["default"],k=p["default"],D=m["default"],j=f["default"],M=d["default"];S.async=M;var R=k;if("undefined"!=typeof window&&"object"==typeof window.__PROMISE_INSTRUMENTATION__){var L=window.__PROMISE_INSTRUMENTATION__;V("instrument",!0);for(var H in L)L.hasOwnProperty(H)&&y(H,L[H])}v.cast=R,v.Promise=_,v.EventTarget=w,v.all=C,v.allSettled=O,v.race=E,v.hash=P,v.hashSettled=A,v.rethrow=T,v.defer=N,v.denodeify=x,v.configure=V,v.on=y,v.off=g,v.resolve=k,v.reject=D,v.async=b,v.map=I,v.filter=j}),e("rsvp.umd",["./rsvp"],function(t){"use strict";var r=t.Promise,n=t.allSettled,i=t.hash,a=t.hashSettled,s=t.denodeify,o=t.on,u=t.off,l=t.map,c=t.filter,h=t.resolve,p=t.reject,m=t.rethrow,f=t.all,d=t.defer,v=t.EventTarget,b=t.configure,y=t.race,g=t.async,_={race:y,Promise:r,allSettled:n,hash:i,hashSettled:a,denodeify:s,on:o,off:u,map:l,filter:c,resolve:h,reject:p,all:f,rethrow:m,defer:d,EventTarget:v,configure:b,async:g};"function"==typeof e&&e.amd?e(function(){return _}):"undefined"!=typeof module&&module.exports?module.exports=_:"undefined"!=typeof this&&(this.RSVP=_)}),e("rsvp/-internal",["./utils","./instrument","./config","exports"],function(e,t,r,n){"use strict";function i(){return new TypeError("A promises callback cannot return that same promise.")}function a(){}function s(e){try{return e.then}catch(t){return T.error=t,T}}function o(e,t,r,n){try{e.call(t,r,n)}catch(i){return i}}function u(e,t,r){O.async(function(e){var n=!1,i=o(r,t,function(r){n||(n=!0,t!==r?h(e,r):m(e,r))},function(t){n||(n=!0,f(e,t))},"Settle: "+(e._label||" unknown promise"));!n&&i&&(n=!0,f(e,i))},e)}function l(e,t){t._state===P?m(e,t._result):e._state===A?f(e,t._result):d(t,void 0,function(r){t!==r?h(e,r):m(e,r)},function(t){f(e,t)})}function c(e,t){if(t.constructor===e.constructor)l(e,t);else{var r=s(t);r===T?f(e,T.error):void 0===r?m(e,t):x(r)?u(e,t,r):m(e,t)}}function h(e,t){e===t?m(e,t):w(t)?c(e,t):m(e,t)}function p(e){e._onerror&&e._onerror(e._result),v(e)}function m(e,t){e._state===E&&(e._result=t,e._state=P,0===e._subscribers.length?O.instrument&&C("fulfilled",e):O.async(v,e))}function f(e,t){e._state===E&&(e._state=A,e._result=t,O.async(p,e))}function d(e,t,r,n){var i=e._subscribers,a=i.length;e._onerror=null,i[a]=t,i[a+P]=r,i[a+A]=n,0===a&&e._state&&O.async(v,e)}function v(e){var t=e._subscribers,r=e._state;if(O.instrument&&C(r===P?"fulfilled":"rejected",e),0!==t.length){for(var n,i,a=e._result,s=0;se;e+=2){var t=d[e],r=d[e+1];t(r),d[e]=void 0,d[e+1]=void 0}l=0}function u(){try{{var e=r("vertx");e.runOnLoop||e.runOnContext}return n()}catch(t){return s()}}var l=0;e["default"]=function(e,t){d[l]=e,d[l+1]=t,l+=2,2===l&&c()};var c,h="undefined"!=typeof window?window:void 0,p=h||{},m=p.MutationObserver||p.WebKitMutationObserver,f="undefined"!=typeof Uint8ClampedArray&&"undefined"!=typeof importScripts&&"undefined"!=typeof MessageChannel,d=new Array(1e3);c="undefined"!=typeof process&&"[object process]"==={}.toString.call(process)?t():m?i():f?a():void 0===h&&"function"==typeof r?u():s()}),e("rsvp/config",["./events","exports"],function(e,t){"use strict";function r(e,t){return"onerror"===e?void i.on("error",t):2!==arguments.length?i[e]:void(i[e]=t)}var n=e["default"],i={instrument:!1};n.mixin(i),t.config=i,t.configure=r}),e("rsvp/defer",["./promise","exports"],function(e,t){"use strict";var r=e["default"];t["default"]=function(e){var t={};return t.promise=new r(function(e,r){t.resolve=e,t.reject=r},e),t}}),e("rsvp/enumerator",["./utils","./-internal","exports"],function(e,t,r){"use strict";function n(e,t,r){return e===h?{state:"fulfilled",value:r}:{state:"rejected",reason:r}}function i(e,t,r,n){this._instanceConstructor=e,this.promise=new e(o,n),this._abortOnReject=r,this._validateInput(t)?(this._input=t,this.length=t.length,this._remaining=t.length,this._init(),0===this.length?l(this.promise,this._result):(this.length=this.length||0,this._enumerate(),0===this._remaining&&l(this.promise,this._result))):u(this.promise,this._validationError())}var a=e.isArray,s=e.isMaybeThenable,o=t.noop,u=t.reject,l=t.fulfill,c=t.subscribe,h=t.FULFILLED,p=t.REJECTED,m=t.PENDING;r.makeSettledResult=n,i.prototype._validateInput=function(e){return a(e)},i.prototype._validationError=function(){return new Error("Array Methods must be provided an Array")},i.prototype._init=function(){this._result=new Array(this.length)},r["default"]=i,i.prototype._enumerate=function(){for(var e=this.length,t=this.promise,r=this._input,n=0;t._state===m&&e>n;n++)this._eachEntry(r[n],n)},i.prototype._eachEntry=function(e,t){var r=this._instanceConstructor;s(e)?e.constructor===r&&e._state!==m?(e._onerror=null,this._settledAt(e._state,t,e._result)):this._willSettleAt(r.resolve(e),t):(this._remaining--,this._result[t]=this._makeResult(h,t,e))},i.prototype._settledAt=function(e,t,r){var n=this.promise;n._state===m&&(this._remaining--,this._abortOnReject&&e===p?u(n,r):this._result[t]=this._makeResult(e,t,r)),0===this._remaining&&l(n,this._result)},i.prototype._makeResult=function(e,t,r){return r},i.prototype._willSettleAt=function(e,t){var r=this;c(e,void 0,function(e){r._settledAt(h,t,e)},function(e){r._settledAt(p,t,e)})}}),e("rsvp/events",["exports"],function(e){"use strict";function t(e,t){for(var r=0,n=e.length;n>r;r++)if(e[r]===t)return r;return-1}function r(e){var t=e._promiseCallbacks;return t||(t=e._promiseCallbacks={}),t}e["default"]={mixin:function(e){return e.on=this.on,e.off=this.off,e.trigger=this.trigger,e._promiseCallbacks=void 0,e},on:function(e,n){var i,a=r(this);i=a[e],i||(i=a[e]=[]),-1===t(i,n)&&i.push(n)},off:function(e,n){var i,a,s=r(this);return n?(i=s[e],a=t(i,n),void(-1!==a&&i.splice(a,1))):void(s[e]=[])},trigger:function(e,t){var n,i,a=r(this);if(n=a[e])for(var s=0;so;o++)s[o]=t(e[o]);return n.all(s,r).then(function(t){for(var r=new Array(a),n=0,i=0;a>i;i++)t[i]&&(r[n]=e[i],n++);return r.length=n,r})})}}),e("rsvp/hash-settled",["./promise","./enumerator","./promise-hash","./utils","exports"],function(e,t,r,n,i){"use strict";function a(e,t,r){this._superConstructor(e,t,!1,r)}var s=e["default"],o=t.makeSettledResult,u=r["default"],l=t["default"],c=n.o_create;a.prototype=c(u.prototype),a.prototype._superConstructor=l,a.prototype._makeResult=o,a.prototype._validationError=function(){return new Error("hashSettled must be called with an object")},i["default"]=function(e,t){return new a(s,e,t).promise}}),e("rsvp/hash",["./promise","./promise-hash","exports"],function(e,t,r){"use strict";var n=e["default"],i=t["default"];r["default"]=function(e,t){return new i(n,e,t).promise}}),e("rsvp/instrument",["./config","./utils","exports"],function(e,t,r){"use strict";function n(){setTimeout(function(){for(var e,t=0;to;o++)s[o]=t(e[o]);return n.all(s,r)})}}),e("rsvp/node",["./promise","./-internal","./utils","exports"],function(e,t,r,n){"use strict";function i(){this.value=void 0}function a(e){try{return e.then}catch(t){return y.value=t,y}}function s(e,t,r){try{e.apply(t,r)}catch(n){return y.value=n,y}}function o(e,t){for(var r,n,i={},a=e.length,s=new Array(a),o=0;a>o;o++)s[o]=e[o];for(n=0;nn;n++)r[n-1]=e[n];return r}function l(e,t){return{then:function(r,n){return e.call(t,r,n)}}}function c(e,t,r,n){var i=s(r,n,t);return i===y&&v(e,i.value),e}function h(e,t,r,n){return m.all(t).then(function(t){var i=s(r,n,t);return i===y&&v(e,i.value),e})}function p(e){return e&&"object"==typeof e?e.constructor===m?!0:a(e):!1}var m=e["default"],f=t.noop,d=t.resolve,v=t.reject,b=r.isArray,y=new i,g=new i;n["default"]=function(e,t){var r=function(){for(var r,n=this,i=arguments.length,a=new Array(i+1),s=!1,y=0;i>y;++y){if(r=arguments[y],!s){if(s=p(r),s===g){var _=new m(f);return v(_,g.value),_}s&&s!==!0&&(r=l(s,r))}a[y]=r}var w=new m(f);return a[i]=function(e,r){e?v(w,e):void 0===t?d(w,r):t===!0?d(w,u(arguments)):b(t)?d(w,o(arguments,t)):d(w,r)},s?h(w,a,e,n):c(w,a,e,n)};return r.__proto__=e,r}}),e("rsvp/promise-hash",["./enumerator","./-internal","./utils","exports"],function(e,t,r,n){"use strict";function i(e,t,r){this._superConstructor(e,t,!0,r)}var a=e["default"],s=t.PENDING,o=r.o_create;n["default"]=i,i.prototype=o(a.prototype),i.prototype._superConstructor=a,i.prototype._init=function(){this._result={}},i.prototype._validateInput=function(e){return e&&"object"==typeof e},i.prototype._validationError=function(){return new Error("Promise.hash must be called with an object")},i.prototype._enumerate=function(){var e=this.promise,t=this._input,r=[];for(var n in t)e._state===s&&t.hasOwnProperty(n)&&r.push({position:n,entry:t[n]});var i=r.length;this._remaining=i;for(var a,o=0;e._state===s&&i>o;o++)a=r[o],this._eachEntry(a.entry,a.position)}}),e("rsvp/promise",["./config","./instrument","./utils","./-internal","./promise/all","./promise/race","./promise/resolve","./promise/reject","exports"],function(e,t,r,n,i,a,s,o,u){"use strict";function l(){throw new TypeError("You must pass a resolver function as the first argument to the promise constructor")}function c(){throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.")}function h(e,t){this._id=A++,this._label=t,this._state=void 0,this._result=void 0,this._subscribers=[],p.instrument&&m("created",this),v!==e&&(f(e)||l(),this instanceof h||c(),y(this,e))}var p=e.config,m=t["default"],f=r.isFunction,d=r.now,v=n.noop,b=n.subscribe,y=n.initializePromise,g=n.invokeCallback,_=n.FULFILLED,w=n.REJECTED,x=i["default"],C=a["default"],O=s["default"],E=o["default"],P="rsvp_"+d()+"-",A=0;u["default"]=h,h.cast=O,h.all=x,h.race=C,h.resolve=O,h.reject=E,h.prototype={constructor:h,_guidKey:P,_onerror:function(e){p.trigger("error",e)},then:function(e,t,r){var n=this,i=n._state;if(i===_&&!e||i===w&&!t)return p.instrument&&m("chained",this,this),this;n._onerror=null;var a=new this.constructor(v,r),s=n._result;if(p.instrument&&m("chained",n,a),i){var o=arguments[i-1];p.async(function(){g(i,a,o,s)})}else b(n,a,e,t);return a},"catch":function(e,t){return this.then(null,e,t)},"finally":function(e,t){var r=this.constructor;return this.then(function(t){return r.resolve(e()).then(function(){return t})},function(t){return r.resolve(e()).then(function(){throw t})},t)}}}),e("rsvp/promise/all",["../enumerator","exports"],function(e,t){"use strict";var r=e["default"];t["default"]=function(e,t){return new r(this,e,!0,t).promise}}),e("rsvp/promise/race",["../utils","../-internal","exports"],function(e,t,r){"use strict";var n=e.isArray,i=t.noop,a=t.resolve,s=t.reject,o=t.subscribe,u=t.PENDING;r["default"]=function(e,t){function r(e){a(h,e)}function l(e){s(h,e)}var c=this,h=new c(i,t);if(!n(e))return s(h,new TypeError("You must pass an array to race.")),h;for(var p=e.length,m=0;h._state===u&&p>m;m++)o(c.resolve(e[m]),void 0,r,l);return h}}),e("rsvp/promise/reject",["../-internal","exports"],function(e,t){"use strict";var r=e.noop,n=e.reject;t["default"]=function(e,t){var i=this,a=new i(r,t);return n(a,e),a}}),e("rsvp/promise/resolve",["../-internal","exports"],function(e,t){"use strict";var r=e.noop,n=e.resolve;t["default"]=function(e,t){var i=this;if(e&&"object"==typeof e&&e.constructor===i)return e;var a=new i(r,t);return n(a,e),a}}),e("rsvp/race",["./promise","exports"],function(e,t){"use strict";var r=e["default"];t["default"]=function(e,t){return r.race(e,t)}}),e("rsvp/reject",["./promise","exports"],function(e,t){"use strict";var r=e["default"];t["default"]=function(e,t){return r.reject(e,t)}}),e("rsvp/resolve",["./promise","exports"],function(e,t){"use strict";var r=e["default"];t["default"]=function(e,t){return r.resolve(e,t)}}),e("rsvp/rethrow",["exports"],function(e){"use strict";e["default"]=function(e){throw setTimeout(function(){throw e}),e}}),e("rsvp/utils",["exports"],function(e){"use strict";function t(e){return"function"==typeof e||"object"==typeof e&&null!==e}function r(e){return"function"==typeof e}function n(e){return"object"==typeof e&&null!==e}function i(){}e.objectOrFunction=t,e.isFunction=r,e.isMaybeThenable=n;var a;a=Array.isArray?Array.isArray:function(e){return"[object Array]"===Object.prototype.toString.call(e)};var s=a;e.isArray=s;var o=Date.now||function(){return(new Date).getTime()};e.now=o;var u=Object.create||function(e){if(arguments.length>1)throw new Error("Second argument not supported"); +if("object"!=typeof e)throw new TypeError("Argument must be an object");return i.prototype=e,new i};e.o_create=u}),t("ember")}(); \ No newline at end of file diff --git a/bower_components/ember/ember.prod.js b/bower_components/ember/ember.prod.js new file mode 100644 index 0000000..db05597 --- /dev/null +++ b/bower_components/ember/ember.prod.js @@ -0,0 +1,47888 @@ +/*! + * @overview Ember - JavaScript Application Framework + * @copyright Copyright 2011-2014 Tilde Inc. and contributors + * Portions Copyright 2006-2011 Strobe Inc. + * Portions Copyright 2008-2011 Apple Inc. All rights reserved. + * @license Licensed under MIT license + * See https://raw.github.com/emberjs/ember.js/master/LICENSE + * @version 1.8.0 + */ + +(function() { +var enifed, requireModule, eriuqer, requirejs, Ember; + +(function() { + Ember = this.Ember = this.Ember || {}; + if (typeof Ember === 'undefined') { Ember = {}; }; + + if (typeof Ember.__loader === 'undefined') { + var registry = {}, seen = {}; + + enifed = function(name, deps, callback) { + registry[name] = { deps: deps, callback: callback }; + }; + + requirejs = eriuqer = requireModule = function(name) { + if (seen.hasOwnProperty(name)) { return seen[name]; } + seen[name] = {}; + + if (!registry[name]) { + throw new Error("Could not find module " + name); + } + + var mod = registry[name]; + var deps = mod.deps; + var callback = mod.callback; + var reified = []; + var exports; + + for (var i=0, l=deps.length; i 3) { + args = new Array(length - 3); + for (var i = 3; i < length; i++) { + args[i-3] = arguments[i]; + } + } else { + args = undefined; + } + + if (!this.currentInstance) { createAutorun(this); } + return this.currentInstance.schedule(queueName, target, method, args, false, stack); + }, + + deferOnce: function(queueName, target, method /* , args */) { + if (!method) { + method = target; + target = null; + } + + if (isString(method)) { + method = target[method]; + } + + var stack = this.DEBUG ? new Error() : undefined; + var length = arguments.length; + var args; + + if (length > 3) { + args = new Array(length - 3); + for (var i = 3; i < length; i++) { + args[i-3] = arguments[i]; + } + } else { + args = undefined; + } + + if (!this.currentInstance) { + createAutorun(this); + } + return this.currentInstance.schedule(queueName, target, method, args, true, stack); + }, + + setTimeout: function() { + var l = arguments.length; + var args = new Array(l); + + for (var x = 0; x < l; x++) { + args[x] = arguments[x]; + } + + var length = args.length, + method, wait, target, + methodOrTarget, methodOrWait, methodOrArgs; + + if (length === 0) { + return; + } else if (length === 1) { + method = args.shift(); + wait = 0; + } else if (length === 2) { + methodOrTarget = args[0]; + methodOrWait = args[1]; + + if (isFunction(methodOrWait) || isFunction(methodOrTarget[methodOrWait])) { + target = args.shift(); + method = args.shift(); + wait = 0; + } else if (isCoercableNumber(methodOrWait)) { + method = args.shift(); + wait = args.shift(); + } else { + method = args.shift(); + wait = 0; + } + } else { + var last = args[args.length - 1]; + + if (isCoercableNumber(last)) { + wait = args.pop(); + } else { + wait = 0; + } + + methodOrTarget = args[0]; + methodOrArgs = args[1]; + + if (isFunction(methodOrArgs) || (isString(methodOrArgs) && + methodOrTarget !== null && + methodOrArgs in methodOrTarget)) { + target = args.shift(); + method = args.shift(); + } else { + method = args.shift(); + } + } + + var executeAt = now() + parseInt(wait, 10); + + if (isString(method)) { + method = target[method]; + } + + var onError = getOnError(this.options); + + function fn() { + if (onError) { + try { + method.apply(target, args); + } catch (e) { + onError(e); + } + } else { + method.apply(target, args); + } + } + + // find position to insert + var i = searchTimer(executeAt, this._timers); + + this._timers.splice(i, 0, executeAt, fn); + + updateLaterTimer(this, executeAt, wait); + + return fn; + }, + + throttle: function(target, method /* , args, wait, [immediate] */) { + var backburner = this; + var args = arguments; + var immediate = pop.call(args); + var wait, throttler, index, timer; + + if (isNumber(immediate) || isString(immediate)) { + wait = immediate; + immediate = true; + } else { + wait = pop.call(args); + } + + wait = parseInt(wait, 10); + + index = findThrottler(target, method, this._throttlers); + if (index > -1) { return this._throttlers[index]; } // throttled + + timer = global.setTimeout(function() { + if (!immediate) { + backburner.run.apply(backburner, args); + } + var index = findThrottler(target, method, backburner._throttlers); + if (index > -1) { + backburner._throttlers.splice(index, 1); + } + }, wait); + + if (immediate) { + this.run.apply(this, args); + } + + throttler = [target, method, timer]; + + this._throttlers.push(throttler); + + return throttler; + }, + + debounce: function(target, method /* , args, wait, [immediate] */) { + var backburner = this; + var args = arguments; + var immediate = pop.call(args); + var wait, index, debouncee, timer; + + if (isNumber(immediate) || isString(immediate)) { + wait = immediate; + immediate = false; + } else { + wait = pop.call(args); + } + + wait = parseInt(wait, 10); + // Remove debouncee + index = findDebouncee(target, method, this._debouncees); + + if (index > -1) { + debouncee = this._debouncees[index]; + this._debouncees.splice(index, 1); + clearTimeout(debouncee[2]); + } + + timer = global.setTimeout(function() { + if (!immediate) { + backburner.run.apply(backburner, args); + } + var index = findDebouncee(target, method, backburner._debouncees); + if (index > -1) { + backburner._debouncees.splice(index, 1); + } + }, wait); + + if (immediate && index === -1) { + backburner.run.apply(backburner, args); + } + + debouncee = [ + target, + method, + timer + ]; + + backburner._debouncees.push(debouncee); + + return debouncee; + }, + + cancelTimers: function() { + var clearItems = function(item) { + clearTimeout(item[2]); + }; + + each(this._throttlers, clearItems); + this._throttlers = []; + + each(this._debouncees, clearItems); + this._debouncees = []; + + if (this._laterTimer) { + clearTimeout(this._laterTimer); + this._laterTimer = null; + } + this._timers = []; + + if (this._autorun) { + clearTimeout(this._autorun); + this._autorun = null; + } + }, + + hasTimers: function() { + return !!this._timers.length || !!this._debouncees.length || !!this._throttlers.length || this._autorun; + }, + + cancel: function(timer) { + var timerType = typeof timer; + + if (timer && timerType === 'object' && timer.queue && timer.method) { // we're cancelling a deferOnce + return timer.queue.cancel(timer); + } else if (timerType === 'function') { // we're cancelling a setTimeout + for (var i = 0, l = this._timers.length; i < l; i += 2) { + if (this._timers[i + 1] === timer) { + this._timers.splice(i, 2); // remove the two elements + if (i === 0) { + if (this._laterTimer) { // Active timer? Then clear timer and reset for future timer + clearTimeout(this._laterTimer); + this._laterTimer = null; + } + if (this._timers.length > 0) { // Update to next available timer when available + updateLaterTimer(this, this._timers[0], this._timers[0] - now()); + } + } + return true; + } + } + } else if (Object.prototype.toString.call(timer) === "[object Array]"){ // we're cancelling a throttle or debounce + return this._cancelItem(findThrottler, this._throttlers, timer) || + this._cancelItem(findDebouncee, this._debouncees, timer); + } else { + return; // timer was null or not a timer + } + }, + + _cancelItem: function(findMethod, array, timer){ + var item, index; + + if (timer.length < 3) { return false; } + + index = findMethod(timer[0], timer[1], array); + + if (index > -1) { + + item = array[index]; + + if (item[2] === timer[2]) { + array.splice(index, 1); + clearTimeout(timer[2]); + return true; + } + } + + return false; + } + }; + + Backburner.prototype.schedule = Backburner.prototype.defer; + Backburner.prototype.scheduleOnce = Backburner.prototype.deferOnce; + Backburner.prototype.later = Backburner.prototype.setTimeout; + + if (needsIETryCatchFix) { + var originalRun = Backburner.prototype.run; + Backburner.prototype.run = wrapInTryCatch(originalRun); + + var originalEnd = Backburner.prototype.end; + Backburner.prototype.end = wrapInTryCatch(originalEnd); + } + + function getOnError(options) { + return options.onError || (options.onErrorTarget && options.onErrorTarget[options.onErrorMethod]); + } + + function createAutorun(backburner) { + backburner.begin(); + backburner._autorun = global.setTimeout(function() { + backburner._autorun = null; + backburner.end(); + }); + } + + function updateLaterTimer(backburner, executeAt, wait) { + var n = now(); + if (!backburner._laterTimer || executeAt < backburner._laterTimerExpiresAt || backburner._laterTimerExpiresAt < n) { + + if (backburner._laterTimer) { + // Clear when: + // - Already expired + // - New timer is earlier + clearTimeout(backburner._laterTimer); + + if (backburner._laterTimerExpiresAt < n) { // If timer was never triggered + // Calculate the left-over wait-time + wait = Math.max(0, executeAt - n); + } + } + + backburner._laterTimer = global.setTimeout(function() { + backburner._laterTimer = null; + backburner._laterTimerExpiresAt = null; + executeTimers(backburner); + }, wait); + + backburner._laterTimerExpiresAt = n + wait; + } + } + + function executeTimers(backburner) { + var n = now(); + var fns, i, l; + + backburner.run(function() { + i = searchTimer(n, backburner._timers); + + fns = backburner._timers.splice(0, i); + + for (i = 1, l = fns.length; i < l; i += 2) { + backburner.schedule(backburner.options.defaultQueue, null, fns[i]); + } + }); + + if (backburner._timers.length) { + updateLaterTimer(backburner, backburner._timers[0], backburner._timers[0] - n); + } + } + + function findDebouncee(target, method, debouncees) { + return findItem(target, method, debouncees); + } + + function findThrottler(target, method, throttlers) { + return findItem(target, method, throttlers); + } + + function findItem(target, method, collection) { + var item; + var index = -1; + + for (var i = 0, l = collection.length; i < l; i++) { + item = collection[i]; + if (item[0] === target && item[1] === method) { + index = i; + break; + } + } + + return index; + } + + __exports__["default"] = Backburner; + }); +enifed("backburner.umd", + ["./backburner"], + function(__dependency1__) { + "use strict"; + var Backburner = __dependency1__["default"]; + + /* global define:true module:true window: true */ + if (typeof enifed === 'function' && enifed.amd) { + enifed(function() { return Backburner; }); + } else if (typeof module !== 'undefined' && module.exports) { + module.exports = Backburner; + } else if (typeof this !== 'undefined') { + this['Backburner'] = Backburner; + } + }); +enifed("backburner/binary-search", + ["exports"], + function(__exports__) { + "use strict"; + __exports__["default"] = function binarySearch(time, timers) { + var start = 0; + var end = timers.length - 2; + var middle, l; + + while (start < end) { + // since timers is an array of pairs 'l' will always + // be an integer + l = (end - start) / 2; + + // compensate for the index in case even number + // of pairs inside timers + middle = start + l - (l % 2); + + if (time >= timers[middle]) { + start = middle + 2; + } else { + end = middle; + } + } + + return (time >= timers[start]) ? start + 2 : start; + } + }); +enifed("backburner/deferred-action-queues", + ["./utils","./queue","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var each = __dependency1__.each; + var isString = __dependency1__.isString; + var Queue = __dependency2__["default"]; + + function DeferredActionQueues(queueNames, options) { + var queues = this.queues = {}; + this.queueNames = queueNames = queueNames || []; + + this.options = options; + + each(queueNames, function(queueName) { + queues[queueName] = new Queue(queueName, options[queueName], options); + }); + } + + function noSuchQueue(name) { + throw new Error("You attempted to schedule an action in a queue (" + name + ") that doesn't exist"); + } + + DeferredActionQueues.prototype = { + schedule: function(name, target, method, args, onceFlag, stack) { + var queues = this.queues; + var queue = queues[name]; + + if (!queue) { noSuchQueue(name); } + + if (onceFlag) { + return queue.pushUnique(target, method, args, stack); + } else { + return queue.push(target, method, args, stack); + } + }, + + invoke: function(target, method, args, _, _errorRecordedForStack) { + if (args && args.length > 0) { + method.apply(target, args); + } else { + method.call(target); + } + }, + + invokeWithOnError: function(target, method, args, onError, errorRecordedForStack) { + try { + if (args && args.length > 0) { + method.apply(target, args); + } else { + method.call(target); + } + } catch(error) { + onError(error, errorRecordedForStack); + } + }, + + flush: function() { + var queues = this.queues; + var queueNames = this.queueNames; + var queueName, queue, queueItems, priorQueueNameIndex; + var queueNameIndex = 0; + var numberOfQueues = queueNames.length; + var options = this.options; + var onError = options.onError || (options.onErrorTarget && options.onErrorTarget[options.onErrorMethod]); + var invoke = onError ? this.invokeWithOnError : this.invoke; + + while (queueNameIndex < numberOfQueues) { + queueName = queueNames[queueNameIndex]; + queue = queues[queueName]; + queueItems = queue._queueBeingFlushed = queue._queue.slice(); + queue._queue = []; + queue.targetQueues = Object.create(null); + + var queueOptions = queue.options; // TODO: write a test for this + var before = queueOptions && queueOptions.before; + var after = queueOptions && queueOptions.after; + var target, method, args, errorRecordedForStack; + var queueIndex = 0; + var numberOfQueueItems = queueItems.length; + + if (numberOfQueueItems && before) { + before(); + } + + while (queueIndex < numberOfQueueItems) { + target = queueItems[queueIndex]; + method = queueItems[queueIndex+1]; + args = queueItems[queueIndex+2]; + errorRecordedForStack = queueItems[queueIndex+3]; // Debugging assistance + + // + + if (isString(method)) { + method = target[method]; + } + + // method could have been nullified / canceled during flush + if (method) { + // + // ** Attention intrepid developer ** + // + // To find out the stack of this task when it was scheduled onto + // the run loop, add the following to your app.js: + // + // Ember.run.backburner.DEBUG = true; // NOTE: This slows your app, don't leave it on in production. + // + // Once that is in place, when you are at a breakpoint and navigate + // here in the stack explorer, you can look at `errorRecordedForStack.stack`, + // which will be the captured stack when this job was scheduled. + // + invoke(target, method, args, onError, errorRecordedForStack); + } + + queueIndex += 4; + } + + queue._queueBeingFlushed = null; + if (numberOfQueueItems && after) { + after(); + } + + if ((priorQueueNameIndex = indexOfPriorQueueWithActions(this, queueNameIndex)) !== -1) { + queueNameIndex = priorQueueNameIndex; + } else { + queueNameIndex++; + } + } + } + }; + + function indexOfPriorQueueWithActions(daq, currentQueueIndex) { + var queueName, queue; + + for (var i = 0, l = currentQueueIndex; i <= l; i++) { + queueName = daq.queueNames[i]; + queue = daq.queues[queueName]; + if (queue._queue.length) { return i; } + } + + return -1; + } + + __exports__["default"] = DeferredActionQueues; + }); +enifed("backburner/platform", + ["exports"], + function(__exports__) { + "use strict"; + // In IE 6-8, try/finally doesn't work without a catch. + // Unfortunately, this is impossible to test for since wrapping it in a parent try/catch doesn't trigger the bug. + // This tests for another broken try/catch behavior that only exhibits in the same versions of IE. + var needsIETryCatchFix = (function(e,x){ + try{ x(); } + catch(e) { } // jshint ignore:line + return !!e; + })(); + __exports__.needsIETryCatchFix = needsIETryCatchFix; + }); +enifed("backburner/queue", + ["exports"], + function(__exports__) { + "use strict"; + function Queue(name, options, globalOptions) { + this.name = name; + this.globalOptions = globalOptions || {}; + this.options = options; + this._queue = []; + this.targetQueues = Object.create(null); + this._queueBeingFlushed = undefined; + } + + Queue.prototype = { + push: function(target, method, args, stack) { + var queue = this._queue; + queue.push(target, method, args, stack); + + return { + queue: this, + target: target, + method: method + }; + }, + + pushUniqueWithoutGuid: function(target, method, args, stack) { + var queue = this._queue; + + for (var i = 0, l = queue.length; i < l; i += 4) { + var currentTarget = queue[i]; + var currentMethod = queue[i+1]; + + if (currentTarget === target && currentMethod === method) { + queue[i+2] = args; // replace args + queue[i+3] = stack; // replace stack + return; + } + } + + queue.push(target, method, args, stack); + }, + + targetQueue: function(targetQueue, target, method, args, stack) { + var queue = this._queue; + + for (var i = 0, l = targetQueue.length; i < l; i += 4) { + var currentMethod = targetQueue[i]; + var currentIndex = targetQueue[i + 1]; + + if (currentMethod === method) { + queue[currentIndex + 2] = args; // replace args + queue[currentIndex + 3] = stack; // replace stack + return; + } + } + + targetQueue.push( + method, + queue.push(target, method, args, stack) - 4 + ); + }, + + pushUniqueWithGuid: function(guid, target, method, args, stack) { + var hasLocalQueue = this.targetQueues[guid]; + + if (hasLocalQueue) { + this.targetQueue(hasLocalQueue, target, method, args, stack); + } else { + this.targetQueues[guid] = [ + method, + this._queue.push(target, method, args, stack) - 4 + ]; + } + + return { + queue: this, + target: target, + method: method + }; + }, + + pushUnique: function(target, method, args, stack) { + var queue = this._queue, currentTarget, currentMethod, i, l; + var KEY = this.globalOptions.GUID_KEY; + + if (target && KEY) { + var guid = target[KEY]; + if (guid) { + return this.pushUniqueWithGuid(guid, target, method, args, stack); + } + } + + this.pushUniqueWithoutGuid(target, method, args, stack); + + return { + queue: this, + target: target, + method: method + }; + }, + + // TODO: remove me, only being used for Ember.run.sync + flush: function() { + var queue = this._queue; + var globalOptions = this.globalOptions; + var options = this.options; + var before = options && options.before; + var after = options && options.after; + var onError = globalOptions.onError || (globalOptions.onErrorTarget && globalOptions.onErrorTarget[globalOptions.onErrorMethod]); + var target, method, args, stack, i, l = queue.length; + + this.targetQueues = Object.create(null); + + if (l && before) { before(); } + for (i = 0; i < l; i += 4) { + target = queue[i]; + method = queue[i+1]; + args = queue[i+2]; + stack = queue[i+3]; // Debugging assistance + + // TODO: error handling + if (args && args.length > 0) { + if (onError) { + try { + method.apply(target, args); + } catch (e) { + onError(e); + } + } else { + method.apply(target, args); + } + } else { + if (onError) { + try { + method.call(target); + } catch(e) { + onError(e); + } + } else { + method.call(target); + } + } + } + if (l && after) { after(); } + + // check if new items have been added + if (queue.length > l) { + this._queue = queue.slice(l); + this.flush(); + } else { + this._queue.length = 0; + } + }, + + cancel: function(actionToCancel) { + var queue = this._queue, currentTarget, currentMethod, i, l; + var target = actionToCancel.target; + var method = actionToCancel.method; + var GUID_KEY = this.globalOptions.GUID_KEY; + + if (GUID_KEY && this.targetQueues && target) { + var targetQueue = this.targetQueues[target[GUID_KEY]]; + + if (targetQueue) { + for (i = 0, l = targetQueue.length; i < l; i++) { + if (targetQueue[i] === method) { + targetQueue.splice(i, 1); + } + } + } + } + + for (i = 0, l = queue.length; i < l; i += 4) { + currentTarget = queue[i]; + currentMethod = queue[i+1]; + + if (currentTarget === target && + currentMethod === method) { + queue.splice(i, 4); + return true; + } + } + + // if not found in current queue + // could be in the queue that is being flushed + queue = this._queueBeingFlushed; + if (!queue) { + return; + } + for (i = 0, l = queue.length; i < l; i += 4) { + currentTarget = queue[i]; + currentMethod = queue[i+1]; + + if (currentTarget === target && + currentMethod === method) { + // don't mess with array during flush + // just nullify the method + queue[i+1] = null; + return true; + } + } + } + }; + + __exports__["default"] = Queue; + }); +enifed("backburner/utils", + ["exports"], + function(__exports__) { + "use strict"; + var NUMBER = /\d+/; + + function each(collection, callback) { + for (var i = 0; i < collection.length; i++) { + callback(collection[i]); + } + } + + __exports__.each = each;// Date.now is not available in browsers < IE9 + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility + var now = Date.now || function() { return new Date().getTime(); }; + __exports__.now = now; + function isString(suspect) { + return typeof suspect === 'string'; + } + + __exports__.isString = isString;function isFunction(suspect) { + return typeof suspect === 'function'; + } + + __exports__.isFunction = isFunction;function isNumber(suspect) { + return typeof suspect === 'number'; + } + + __exports__.isNumber = isNumber;function isCoercableNumber(number) { + return isNumber(number) || NUMBER.test(number); + } + + __exports__.isCoercableNumber = isCoercableNumber;function wrapInTryCatch(func) { + return function () { + try { + return func.apply(this, arguments); + } catch (e) { + throw e; + } + }; + } + + __exports__.wrapInTryCatch = wrapInTryCatch; + }); +enifed("calculateVersion", + [], + function() { + "use strict"; + 'use strict'; + + var fs = eriuqer('fs'); + var path = eriuqer('path'); + + module.exports = function () { + var packageVersion = eriuqer('../package.json').version; + var output = [packageVersion]; + var gitPath = path.join(__dirname,'..','.git'); + var headFilePath = path.join(gitPath, 'HEAD'); + + if (packageVersion.indexOf('+') > -1) { + try { + if (fs.existsSync(headFilePath)) { + var headFile = fs.readFileSync(headFilePath, {encoding: 'utf8'}); + var branchName = headFile.split('/').slice(-1)[0].trim(); + var refPath = headFile.split(' ')[1]; + var branchSHA; + + if (refPath) { + var branchPath = path.join(gitPath, refPath.trim()); + branchSHA = fs.readFileSync(branchPath); + } else { + branchSHA = branchName; + } + + output.push(branchSHA.slice(0,10)); + } + } catch (err) { + console.error(err.stack); + } + return output.join('.'); + } else { + return packageVersion; + } + }; + }); +enifed("container", + ["container/container","exports"], + function(__dependency1__, __exports__) { + "use strict"; + /* + Public api for the container is still in flux. + The public api, specified on the application namespace should be considered the stable api. + // @module container + @private + */ + + /* + Flag to enable/disable model factory injections (disabled by default) + If model factory injections are enabled, models should not be + accessed globally (only through `container.lookupFactory('model:modelName'))`); + */ + Ember.MODEL_FACTORY_INJECTIONS = false; + + if (Ember.ENV && typeof Ember.ENV.MODEL_FACTORY_INJECTIONS !== 'undefined') { + Ember.MODEL_FACTORY_INJECTIONS = !!Ember.ENV.MODEL_FACTORY_INJECTIONS; + } + + + var Container = __dependency1__["default"]; + + __exports__["default"] = Container; + }); +enifed("container/container", + ["ember-metal/core","ember-metal/keys","ember-metal/dictionary","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert + var emberKeys = __dependency2__["default"]; + var dictionary = __dependency3__["default"]; + + // A lightweight container that helps to assemble and decouple components. + // Public api for the container is still in flux. + // The public api, specified on the application namespace should be considered the stable api. + function Container(parent) { + this.parent = parent; + this.children = []; + + this.resolver = parent && parent.resolver || function() {}; + + this.registry = dictionary(parent ? parent.registry : null); + this.cache = dictionary(parent ? parent.cache : null); + this.factoryCache = dictionary(parent ? parent.factoryCache : null); + this.resolveCache = dictionary(parent ? parent.resolveCache : null); + this.typeInjections = dictionary(parent ? parent.typeInjections : null); + this.injections = dictionary(null); + this.normalizeCache = dictionary(null); + + this.factoryTypeInjections = dictionary(parent ? parent.factoryTypeInjections : null); + this.factoryInjections = dictionary(null); + + this._options = dictionary(parent ? parent._options : null); + this._typeOptions = dictionary(parent ? parent._typeOptions : null); + } + + Container.prototype = { + + /** + @property parent + @type Container + @default null + */ + parent: null, + + /** + @property children + @type Array + @default [] + */ + children: null, + + /** + @property resolver + @type function + */ + resolver: null, + + /** + @property registry + @type InheritingDict + */ + registry: null, + + /** + @property cache + @type InheritingDict + */ + cache: null, + + /** + @property typeInjections + @type InheritingDict + */ + typeInjections: null, + + /** + @property injections + @type Object + @default {} + */ + injections: null, + + /** + @private + + @property _options + @type InheritingDict + @default null + */ + _options: null, + + /** + @private + + @property _typeOptions + @type InheritingDict + */ + _typeOptions: null, + + /** + Returns a new child of the current container. These children are configured + to correctly inherit from the current container. + + @method child + @return {Container} + */ + child: function() { + var container = new Container(this); + this.children.push(container); + return container; + }, + + /** + Sets a key-value pair on the current container. If a parent container, + has the same key, once set on a child, the parent and child will diverge + as expected. + + @method set + @param {Object} object + @param {String} key + @param {any} value + */ + set: function(object, key, value) { + object[key] = value; + }, + + /** + Registers a factory for later injection. + + Example: + + ```javascript + var container = new Container(); + + container.register('model:user', Person, {singleton: false }); + container.register('fruit:favorite', Orange); + container.register('communication:main', Email, {singleton: false}); + ``` + + @method register + @param {String} fullName + @param {Function} factory + @param {Object} options + */ + register: function(fullName, factory, options) { + + if (factory === undefined) { + throw new TypeError('Attempting to register an unknown factory: `' + fullName + '`'); + } + + var normalizedName = this.normalize(fullName); + + if (normalizedName in this.cache) { + throw new Error('Cannot re-register: `' + fullName +'`, as it has already been looked up.'); + } + + this.registry[normalizedName] = factory; + this._options[normalizedName] = (options || {}); + }, + + /** + Unregister a fullName + + ```javascript + var container = new Container(); + container.register('model:user', User); + + container.lookup('model:user') instanceof User //=> true + + container.unregister('model:user') + container.lookup('model:user') === undefined //=> true + ``` + + @method unregister + @param {String} fullName + */ + unregister: function(fullName) { + + var normalizedName = this.normalize(fullName); + + delete this.registry[normalizedName]; + delete this.cache[normalizedName]; + delete this.factoryCache[normalizedName]; + delete this.resolveCache[normalizedName]; + delete this._options[normalizedName]; + }, + + /** + Given a fullName return the corresponding factory. + + By default `resolve` will retrieve the factory from + its container's registry. + + ```javascript + var container = new Container(); + container.register('api:twitter', Twitter); + + container.resolve('api:twitter') // => Twitter + ``` + + Optionally the container can be provided with a custom resolver. + If provided, `resolve` will first provide the custom resolver + the opportunity to resolve the fullName, otherwise it will fallback + to the registry. + + ```javascript + var container = new Container(); + container.resolver = function(fullName) { + // lookup via the module system of choice + }; + + // the twitter factory is added to the module system + container.resolve('api:twitter') // => Twitter + ``` + + @method resolve + @param {String} fullName + @return {Function} fullName's factory + */ + resolve: function(fullName) { + return resolve(this, this.normalize(fullName)); + }, + + /** + A hook that can be used to describe how the resolver will + attempt to find the factory. + + For example, the default Ember `.describe` returns the full + class name (including namespace) where Ember's resolver expects + to find the `fullName`. + + @method describe + @param {String} fullName + @return {string} described fullName + */ + describe: function(fullName) { + return fullName; + }, + + /** + A hook to enable custom fullName normalization behaviour + + @method normalizeFullName + @param {String} fullName + @return {string} normalized fullName + */ + normalizeFullName: function(fullName) { + return fullName; + }, + + /** + normalize a fullName based on the applications conventions + + @method normalize + @param {String} fullName + @return {string} normalized fullName + */ + normalize: function(fullName) { + return this.normalizeCache[fullName] || ( + this.normalizeCache[fullName] = this.normalizeFullName(fullName) + ); + }, + + /** + @method makeToString + + @param {any} factory + @param {string} fullName + @return {function} toString function + */ + makeToString: function(factory, fullName) { + return factory.toString(); + }, + + /** + Given a fullName return a corresponding instance. + + The default behaviour is for lookup to return a singleton instance. + The singleton is scoped to the container, allowing multiple containers + to all have their own locally scoped singletons. + + ```javascript + var container = new Container(); + container.register('api:twitter', Twitter); + + var twitter = container.lookup('api:twitter'); + + twitter instanceof Twitter; // => true + + // by default the container will return singletons + var twitter2 = container.lookup('api:twitter'); + twitter2 instanceof Twitter; // => true + + twitter === twitter2; //=> true + ``` + + If singletons are not wanted an optional flag can be provided at lookup. + + ```javascript + var container = new Container(); + container.register('api:twitter', Twitter); + + var twitter = container.lookup('api:twitter', { singleton: false }); + var twitter2 = container.lookup('api:twitter', { singleton: false }); + + twitter === twitter2; //=> false + ``` + + @method lookup + @param {String} fullName + @param {Object} options + @return {any} + */ + lookup: function(fullName, options) { + return lookup(this, this.normalize(fullName), options); + }, + + /** + Given a fullName return the corresponding factory. + + @method lookupFactory + @param {String} fullName + @return {any} + */ + lookupFactory: function(fullName) { + return factoryFor(this, this.normalize(fullName)); + }, + + /** + Given a fullName check if the container is aware of its factory + or singleton instance. + + @method has + @param {String} fullName + @return {Boolean} + */ + has: function(fullName) { + return has(this, this.normalize(fullName)); + }, + + /** + Allow registering options for all factories of a type. + + ```javascript + var container = new Container(); + + // if all of type `connection` must not be singletons + container.optionsForType('connection', { singleton: false }); + + container.register('connection:twitter', TwitterConnection); + container.register('connection:facebook', FacebookConnection); + + var twitter = container.lookup('connection:twitter'); + var twitter2 = container.lookup('connection:twitter'); + + twitter === twitter2; // => false + + var facebook = container.lookup('connection:facebook'); + var facebook2 = container.lookup('connection:facebook'); + + facebook === facebook2; // => false + ``` + + @method optionsForType + @param {String} type + @param {Object} options + */ + optionsForType: function(type, options) { + if (this.parent) { illegalChildOperation('optionsForType'); } + + this._typeOptions[type] = options; + }, + + /** + @method options + @param {String} type + @param {Object} options + */ + options: function(type, options) { + this.optionsForType(type, options); + }, + + /** + Used only via `injection`. + + Provides a specialized form of injection, specifically enabling + all objects of one type to be injected with a reference to another + object. + + For example, provided each object of type `controller` needed a `router`. + one would do the following: + + ```javascript + var container = new Container(); + + container.register('router:main', Router); + container.register('controller:user', UserController); + container.register('controller:post', PostController); + + container.typeInjection('controller', 'router', 'router:main'); + + var user = container.lookup('controller:user'); + var post = container.lookup('controller:post'); + + user.router instanceof Router; //=> true + post.router instanceof Router; //=> true + + // both controllers share the same router + user.router === post.router; //=> true + ``` + + @private + @method typeInjection + @param {String} type + @param {String} property + @param {String} fullName + */ + typeInjection: function(type, property, fullName) { + + if (this.parent) { illegalChildOperation('typeInjection'); } + + var fullNameType = fullName.split(':')[0]; + if (fullNameType === type) { + throw new Error('Cannot inject a `' + fullName + '` on other ' + type + '(s). Register the `' + fullName + '` as a different type and perform the typeInjection.'); + } + + addTypeInjection(this.typeInjections, type, property, fullName); + }, + + /** + Defines injection rules. + + These rules are used to inject dependencies onto objects when they + are instantiated. + + Two forms of injections are possible: + + * Injecting one fullName on another fullName + * Injecting one fullName on a type + + Example: + + ```javascript + var container = new Container(); + + container.register('source:main', Source); + container.register('model:user', User); + container.register('model:post', Post); + + // injecting one fullName on another fullName + // eg. each user model gets a post model + container.injection('model:user', 'post', 'model:post'); + + // injecting one fullName on another type + container.injection('model', 'source', 'source:main'); + + var user = container.lookup('model:user'); + var post = container.lookup('model:post'); + + user.source instanceof Source; //=> true + post.source instanceof Source; //=> true + + user.post instanceof Post; //=> true + + // and both models share the same source + user.source === post.source; //=> true + ``` + + @method injection + @param {String} factoryName + @param {String} property + @param {String} injectionName + */ + injection: function(fullName, property, injectionName) { + if (this.parent) { illegalChildOperation('injection'); } + + validateFullName(injectionName); + var normalizedInjectionName = this.normalize(injectionName); + + if (fullName.indexOf(':') === -1) { + return this.typeInjection(fullName, property, normalizedInjectionName); + } + + var normalizedName = this.normalize(fullName); + + if (this.cache[normalizedName]) { + throw new Error("Attempted to register an injection for a type that has already been looked up. ('" + normalizedName + "', '" + property + "', '" + injectionName + "')"); + } + addInjection(this.injections, normalizedName, property, normalizedInjectionName); + }, + + + /** + Used only via `factoryInjection`. + + Provides a specialized form of injection, specifically enabling + all factory of one type to be injected with a reference to another + object. + + For example, provided each factory of type `model` needed a `store`. + one would do the following: + + ```javascript + var container = new Container(); + + container.register('store:main', SomeStore); + + container.factoryTypeInjection('model', 'store', 'store:main'); + + var store = container.lookup('store:main'); + var UserFactory = container.lookupFactory('model:user'); + + UserFactory.store instanceof SomeStore; //=> true + ``` + + @private + @method factoryTypeInjection + @param {String} type + @param {String} property + @param {String} fullName + */ + factoryTypeInjection: function(type, property, fullName) { + if (this.parent) { illegalChildOperation('factoryTypeInjection'); } + + addTypeInjection(this.factoryTypeInjections, type, property, this.normalize(fullName)); + }, + + /** + Defines factory injection rules. + + Similar to regular injection rules, but are run against factories, via + `Container#lookupFactory`. + + These rules are used to inject objects onto factories when they + are looked up. + + Two forms of injections are possible: + + * Injecting one fullName on another fullName + * Injecting one fullName on a type + + Example: + + ```javascript + var container = new Container(); + + container.register('store:main', Store); + container.register('store:secondary', OtherStore); + container.register('model:user', User); + container.register('model:post', Post); + + // injecting one fullName on another type + container.factoryInjection('model', 'store', 'store:main'); + + // injecting one fullName on another fullName + container.factoryInjection('model:post', 'secondaryStore', 'store:secondary'); + + var UserFactory = container.lookupFactory('model:user'); + var PostFactory = container.lookupFactory('model:post'); + var store = container.lookup('store:main'); + + UserFactory.store instanceof Store; //=> true + UserFactory.secondaryStore instanceof OtherStore; //=> false + + PostFactory.store instanceof Store; //=> true + PostFactory.secondaryStore instanceof OtherStore; //=> true + + // and both models share the same source instance + UserFactory.store === PostFactory.store; //=> true + ``` + + @method factoryInjection + @param {String} factoryName + @param {String} property + @param {String} injectionName + */ + factoryInjection: function(fullName, property, injectionName) { + if (this.parent) { illegalChildOperation('injection'); } + + var normalizedName = this.normalize(fullName); + var normalizedInjectionName = this.normalize(injectionName); + + validateFullName(injectionName); + + if (fullName.indexOf(':') === -1) { + return this.factoryTypeInjection(normalizedName, property, normalizedInjectionName); + } + + + if (this.factoryCache[normalizedName]) { + throw new Error('Attempted to register a factoryInjection for a type that has already ' + + 'been looked up. (\'' + normalizedName + '\', \'' + property + '\', \'' + injectionName + '\')'); + } + + addInjection(this.factoryInjections, normalizedName, property, normalizedInjectionName); + }, + + /** + A depth first traversal, destroying the container, its descendant containers and all + their managed objects. + + @method destroy + */ + destroy: function() { + for (var i = 0, length = this.children.length; i < length; i++) { + this.children[i].destroy(); + } + + this.children = []; + + eachDestroyable(this, function(item) { + item.destroy(); + }); + + this.parent = undefined; + this.isDestroyed = true; + }, + + /** + @method reset + */ + reset: function() { + for (var i = 0, length = this.children.length; i < length; i++) { + resetCache(this.children[i]); + } + + resetCache(this); + } + }; + + function resolve(container, normalizedName) { + var cached = container.resolveCache[normalizedName]; + if (cached) { return cached; } + + var resolved = container.resolver(normalizedName) || container.registry[normalizedName]; + container.resolveCache[normalizedName] = resolved; + + return resolved; + } + + function has(container, fullName){ + if (container.cache[fullName]) { + return true; + } + + return !!container.resolve(fullName); + } + + function lookup(container, fullName, options) { + options = options || {}; + + if (container.cache[fullName] && options.singleton !== false) { + return container.cache[fullName]; + } + + var value = instantiate(container, fullName); + + if (value === undefined) { return; } + + if (isSingleton(container, fullName) && options.singleton !== false) { + container.cache[fullName] = value; + } + + return value; + } + + function illegalChildOperation(operation) { + throw new Error(operation + ' is not currently supported on child containers'); + } + + function isSingleton(container, fullName) { + var singleton = option(container, fullName, 'singleton'); + + return singleton !== false; + } + + function buildInjections(container, injections) { + var hash = {}; + + if (!injections) { return hash; } + + var injection, injectable; + + for (var i = 0, length = injections.length; i < length; i++) { + injection = injections[i]; + injectable = lookup(container, injection.fullName); + + if (injectable !== undefined) { + hash[injection.property] = injectable; + } else { + throw new Error('Attempting to inject an unknown injection: `' + injection.fullName + '`'); + } + } + + return hash; + } + + function option(container, fullName, optionName) { + var options = container._options[fullName]; + + if (options && options[optionName] !== undefined) { + return options[optionName]; + } + + var type = fullName.split(':')[0]; + options = container._typeOptions[type]; + + if (options) { + return options[optionName]; + } + } + + function factoryFor(container, fullName) { + var cache = container.factoryCache; + if (cache[fullName]) { + return cache[fullName]; + } + var factory = container.resolve(fullName); + if (factory === undefined) { return; } + + var type = fullName.split(':')[0]; + if (!factory || typeof factory.extend !== 'function' || (!Ember.MODEL_FACTORY_INJECTIONS && type === 'model')) { + // TODO: think about a 'safe' merge style extension + // for now just fallback to create time injection + cache[fullName] = factory; + return factory; + } else { + var injections = injectionsFor(container, fullName); + var factoryInjections = factoryInjectionsFor(container, fullName); + + factoryInjections._toString = container.makeToString(factory, fullName); + + var injectedFactory = factory.extend(injections); + injectedFactory.reopenClass(factoryInjections); + + cache[fullName] = injectedFactory; + + return injectedFactory; + } + } + + function injectionsFor(container, fullName) { + var splitName = fullName.split(':'); + var type = splitName[0]; + var injections = []; + + injections = injections.concat(container.typeInjections[type] || []); + injections = injections.concat(container.injections[fullName] || []); + + injections = buildInjections(container, injections); + injections._debugContainerKey = fullName; + injections.container = container; + + return injections; + } + + function factoryInjectionsFor(container, fullName) { + var splitName = fullName.split(':'); + var type = splitName[0]; + var factoryInjections = []; + + factoryInjections = factoryInjections.concat(container.factoryTypeInjections[type] || []); + factoryInjections = factoryInjections.concat(container.factoryInjections[fullName] || []); + + factoryInjections = buildInjections(container, factoryInjections); + factoryInjections._debugContainerKey = fullName; + + return factoryInjections; + } + + function instantiate(container, fullName) { + var factory = factoryFor(container, fullName); + + if (option(container, fullName, 'instantiate') === false) { + return factory; + } + + if (factory) { + if (typeof factory.create !== 'function') { + throw new Error('Failed to create an instance of \'' + fullName + '\'. ' + + 'Most likely an improperly defined class or an invalid module export.'); + } + + if (typeof factory.extend === 'function') { + // assume the factory was extendable and is already injected + return factory.create(); + } else { + // assume the factory was extendable + // to create time injections + // TODO: support new'ing for instantiation and merge injections for pure JS Functions + return factory.create(injectionsFor(container, fullName)); + } + } + } + + function eachDestroyable(container, callback) { + var cache = container.cache; + var keys = emberKeys(cache); + var key, value; + + for (var i = 0, l = keys.length; i < l; i++) { + key = keys[i]; + value = cache[key]; + + if (option(container, key, 'instantiate') !== false) { + callback(value); + } + } + } + + function resetCache(container) { + eachDestroyable(container, function(value) { + value.destroy(); + }); + + container.cache.dict = dictionary(null); + } + + function addTypeInjection(rules, type, property, fullName) { + var injections = rules[type]; + + if (!injections) { + injections = []; + rules[type] = injections; + } + + injections.push({ + property: property, + fullName: fullName + }); + } + + var VALID_FULL_NAME_REGEXP = /^[^:]+.+:[^:]+$/; + function validateFullName(fullName) { + if (!VALID_FULL_NAME_REGEXP.test(fullName)) { + throw new TypeError('Invalid Fullname, expected: `type:name` got: ' + fullName); + } + return true; + } + + function addInjection(rules, factoryName, property, injectionName) { + var injections = rules[factoryName] = rules[factoryName] || []; + injections.push({ + property: property, + fullName: injectionName + }); + } + + __exports__["default"] = Container; + }); +enifed("ember-application", + ["ember-metal/core","ember-runtime/system/lazy_load","ember-application/system/dag","ember-application/system/resolver","ember-application/system/application","ember-application/ext/controller"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__) { + "use strict"; + var Ember = __dependency1__["default"]; + var runLoadHooks = __dependency2__.runLoadHooks; + + /** + Ember Application + + @module ember + @submodule ember-application + @requires ember-views, ember-routing + */ + + var DAG = __dependency3__["default"]; + var Resolver = __dependency4__.Resolver; + var DefaultResolver = __dependency4__["default"]; + var Application = __dependency5__["default"]; + // side effect of extending ControllerMixin + + Ember.Application = Application; + Ember.DAG = DAG; + Ember.Resolver = Resolver; + Ember.DefaultResolver = DefaultResolver; + + runLoadHooks('Ember.Application', Application); + }); +enifed("ember-application/ext/controller", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/error","ember-metal/utils","ember-metal/computed","ember-runtime/mixins/controller","ember-routing/system/controller_for","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-application + */ + + var Ember = __dependency1__["default"]; + // Ember.assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var EmberError = __dependency4__["default"]; + var inspect = __dependency5__.inspect; + var computed = __dependency6__.computed; + var ControllerMixin = __dependency7__["default"]; + var meta = __dependency5__.meta; + var controllerFor = __dependency8__["default"]; + + function verifyNeedsDependencies(controller, container, needs) { + var dependency, i, l; + var missing = []; + + for (i=0, l=needs.length; i 1 ? 'they' : 'it') + " could not be found"); + } + } + + var defaultControllersComputedProperty = computed(function() { + var controller = this; + + return { + needs: get(controller, 'needs'), + container: get(controller, 'container'), + unknownProperty: function(controllerName) { + var needs = this.needs; + var dependency, i, l; + + for (i=0, l=needs.length; i 0) { + + if (this.container) { + verifyNeedsDependencies(this, this.container, needs); + } + + // if needs then initialize controllers proxy + get(this, 'controllers'); + } + + this._super.apply(this, arguments); + }, + + /** + @method controllerFor + @see {Ember.Route#controllerFor} + @deprecated Use `needs` instead + */ + controllerFor: function(controllerName) { + return controllerFor(get(this, 'container'), controllerName); + }, + + /** + Stores the instances of other controllers available from within + this controller. Any controller listed by name in the `needs` + property will be accessible by name through this property. + + ```javascript + App.CommentsController = Ember.ArrayController.extend({ + needs: ['post'], + postTitle: function(){ + var currentPost = this.get('controllers.post'); // instance of App.PostController + return currentPost.get('title'); + }.property('controllers.post.title') + }); + ``` + + @see {Ember.ControllerMixin#needs} + @property {Object} controllers + @default null + */ + controllers: defaultControllersComputedProperty + }); + + __exports__["default"] = ControllerMixin; + }); +enifed("ember-application/system/application", + ["ember-metal","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/lazy_load","ember-application/system/dag","ember-runtime/system/namespace","ember-runtime/mixins/deferred","ember-application/system/resolver","ember-metal/platform","ember-metal/run_loop","ember-metal/utils","container/container","ember-runtime/controllers/controller","ember-metal/enumerable_utils","ember-runtime/controllers/object_controller","ember-runtime/controllers/array_controller","ember-handlebars/controls/select","ember-views/system/event_dispatcher","ember-views/system/jquery","ember-routing/system/route","ember-routing/system/router","ember-routing/location/hash_location","ember-routing/location/history_location","ember-routing/location/auto_location","ember-routing/location/none_location","ember-routing/system/cache","ember-metal/core","ember-handlebars-compiler","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __dependency18__, __dependency19__, __dependency20__, __dependency21__, __dependency22__, __dependency23__, __dependency24__, __dependency25__, __dependency26__, __dependency27__, __dependency28__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-application + */ + + var Ember = __dependency1__["default"]; + // Ember.FEATURES, Ember.deprecate, Ember.assert, Ember.libraries, LOG_VERSION, Namespace, BOOTED + var get = __dependency2__.get; + var set = __dependency3__.set; + var runLoadHooks = __dependency4__.runLoadHooks; + var DAG = __dependency5__["default"]; + var Namespace = __dependency6__["default"]; + var DeferredMixin = __dependency7__["default"]; + var DefaultResolver = __dependency8__["default"]; + var create = __dependency9__.create; + var run = __dependency10__["default"]; + var canInvoke = __dependency11__.canInvoke; + var Container = __dependency12__["default"]; + var Controller = __dependency13__["default"]; + var EnumerableUtils = __dependency14__["default"]; + var ObjectController = __dependency15__["default"]; + var ArrayController = __dependency16__["default"]; + var SelectView = __dependency17__["default"]; + var EventDispatcher = __dependency18__["default"]; + //import ContainerDebugAdapter from "ember-extension-support/container_debug_adapter"; + var jQuery = __dependency19__["default"]; + var Route = __dependency20__["default"]; + var Router = __dependency21__["default"]; + var HashLocation = __dependency22__["default"]; + var HistoryLocation = __dependency23__["default"]; + var AutoLocation = __dependency24__["default"]; + var NoneLocation = __dependency25__["default"]; + var BucketCache = __dependency26__["default"]; + + var K = __dependency27__.K; + var EmberHandlebars = __dependency28__["default"]; + + var ContainerDebugAdapter; + function props(obj) { + var properties = []; + + for (var key in obj) { + properties.push(key); + } + + return properties; + } + + /** + An instance of `Ember.Application` is the starting point for every Ember + application. It helps to instantiate, initialize and coordinate the many + objects that make up your app. + + Each Ember app has one and only one `Ember.Application` object. In fact, the + very first thing you should do in your application is create the instance: + + ```javascript + window.App = Ember.Application.create(); + ``` + + Typically, the application object is the only global variable. All other + classes in your app should be properties on the `Ember.Application` instance, + which highlights its first role: a global namespace. + + For example, if you define a view class, it might look like this: + + ```javascript + App.MyView = Ember.View.extend(); + ``` + + By default, calling `Ember.Application.create()` will automatically initialize + your application by calling the `Ember.Application.initialize()` method. If + you need to delay initialization, you can call your app's `deferReadiness()` + method. When you are ready for your app to be initialized, call its + `advanceReadiness()` method. + + You can define a `ready` method on the `Ember.Application` instance, which + will be run by Ember when the application is initialized. + + Because `Ember.Application` inherits from `Ember.Namespace`, any classes + you create will have useful string representations when calling `toString()`. + See the `Ember.Namespace` documentation for more information. + + While you can think of your `Ember.Application` as a container that holds the + other classes in your application, there are several other responsibilities + going on under-the-hood that you may want to understand. + + ### Event Delegation + + Ember uses a technique called _event delegation_. This allows the framework + to set up a global, shared event listener instead of requiring each view to + do it manually. For example, instead of each view registering its own + `mousedown` listener on its associated element, Ember sets up a `mousedown` + listener on the `body`. + + If a `mousedown` event occurs, Ember will look at the target of the event and + start walking up the DOM node tree, finding corresponding views and invoking + their `mouseDown` method as it goes. + + `Ember.Application` has a number of default events that it listens for, as + well as a mapping from lowercase events to camel-cased view method names. For + example, the `keypress` event causes the `keyPress` method on the view to be + called, the `dblclick` event causes `doubleClick` to be called, and so on. + + If there is a bubbling browser event that Ember does not listen for by + default, you can specify custom events and their corresponding view method + names by setting the application's `customEvents` property: + + ```javascript + App = Ember.Application.create({ + customEvents: { + // add support for the paste event + paste: "paste" + } + }); + ``` + + By default, the application sets up these event listeners on the document + body. However, in cases where you are embedding an Ember application inside + an existing page, you may want it to set up the listeners on an element + inside the body. + + For example, if only events inside a DOM element with the ID of `ember-app` + should be delegated, set your application's `rootElement` property: + + ```javascript + window.App = Ember.Application.create({ + rootElement: '#ember-app' + }); + ``` + + The `rootElement` can be either a DOM element or a jQuery-compatible selector + string. Note that *views appended to the DOM outside the root element will + not receive events.* If you specify a custom root element, make sure you only + append views inside it! + + To learn more about the advantages of event delegation and the Ember view + layer, and a list of the event listeners that are setup by default, visit the + [Ember View Layer guide](http://emberjs.com/guides/understanding-ember/the-view-layer/#toc_event-delegation). + + ### Initializers + + Libraries on top of Ember can add initializers, like so: + + ```javascript + Ember.Application.initializer({ + name: 'api-adapter', + + initialize: function(container, application) { + application.register('api-adapter:main', ApiAdapter); + } + }); + ``` + + Initializers provide an opportunity to access the container, which + organizes the different components of an Ember application. Additionally + they provide a chance to access the instantiated application. Beyond + being used for libraries, initializers are also a great way to organize + dependency injection or setup in your own application. + + ### Routing + + In addition to creating your application's router, `Ember.Application` is + also responsible for telling the router when to start routing. Transitions + between routes can be logged with the `LOG_TRANSITIONS` flag, and more + detailed intra-transition logging can be logged with + the `LOG_TRANSITIONS_INTERNAL` flag: + + ```javascript + window.App = Ember.Application.create({ + LOG_TRANSITIONS: true, // basic logging of successful transitions + LOG_TRANSITIONS_INTERNAL: true // detailed logging of all routing steps + }); + ``` + + By default, the router will begin trying to translate the current URL into + application state once the browser emits the `DOMContentReady` event. If you + need to defer routing, you can call the application's `deferReadiness()` + method. Once routing can begin, call the `advanceReadiness()` method. + + If there is any setup required before routing begins, you can implement a + `ready()` method on your app that will be invoked immediately before routing + begins. + ``` + + @class Application + @namespace Ember + @extends Ember.Namespace + */ + + var Application = Namespace.extend(DeferredMixin, { + _suppressDeferredDeprecation: true, + + /** + The root DOM element of the Application. This can be specified as an + element or a + [jQuery-compatible selector string](http://api.jquery.com/category/selectors/). + + This is the element that will be passed to the Application's, + `eventDispatcher`, which sets up the listeners for event delegation. Every + view in your application should be a child of the element you specify here. + + @property rootElement + @type DOMElement + @default 'body' + */ + rootElement: 'body', + + /** + The `Ember.EventDispatcher` responsible for delegating events to this + application's views. + + The event dispatcher is created by the application at initialization time + and sets up event listeners on the DOM element described by the + application's `rootElement` property. + + See the documentation for `Ember.EventDispatcher` for more information. + + @property eventDispatcher + @type Ember.EventDispatcher + @default null + */ + eventDispatcher: null, + + /** + The DOM events for which the event dispatcher should listen. + + By default, the application's `Ember.EventDispatcher` listens + for a set of standard DOM events, such as `mousedown` and + `keyup`, and delegates them to your application's `Ember.View` + instances. + + If you would like additional bubbling events to be delegated to your + views, set your `Ember.Application`'s `customEvents` property + to a hash containing the DOM event name as the key and the + corresponding view method name as the value. For example: + + ```javascript + App = Ember.Application.create({ + customEvents: { + // add support for the paste event + paste: "paste" + } + }); + ``` + + @property customEvents + @type Object + @default null + */ + customEvents: null, + + // Start off the number of deferrals at 1. This will be + // decremented by the Application's own `initialize` method. + _readinessDeferrals: 1, + + init: function() { + if (!this.$) { this.$ = jQuery; } + this.__container__ = this.buildContainer(); + + this.Router = this.defaultRouter(); + + this._super(); + + this.scheduleInitialize(); + + Ember.libraries.registerCoreLibrary('Handlebars' + (EmberHandlebars.compile ? '' : '-runtime'), EmberHandlebars.VERSION); + Ember.libraries.registerCoreLibrary('jQuery', jQuery().jquery); + + if ( Ember.LOG_VERSION ) { + Ember.LOG_VERSION = false; // we only need to see this once per Application#init + + var nameLengths = EnumerableUtils.map(Ember.libraries, function(item) { + return get(item, "name.length"); + }); + + var maxNameLength = Math.max.apply(this, nameLengths); + + Ember.libraries.each(function(name, version) { + var spaces = new Array(maxNameLength - name.length + 1).join(" "); + }); + } + }, + + /** + Build the container for the current application. + + Also register a default application view in case the application + itself does not. + + @private + @method buildContainer + @return {Ember.Container} the configured container + */ + buildContainer: function() { + var container = this.__container__ = Application.buildContainer(this); + + return container; + }, + + /** + If the application has not opted out of routing and has not explicitly + defined a router, supply a default router for the application author + to configure. + + This allows application developers to do: + + ```javascript + var App = Ember.Application.create(); + + App.Router.map(function() { + this.resource('posts'); + }); + ``` + + @private + @method defaultRouter + @return {Ember.Router} the default router + */ + + defaultRouter: function() { + if (this.Router === false) { return; } + var container = this.__container__; + + if (this.Router) { + container.unregister('router:main'); + container.register('router:main', this.Router); + } + + return container.lookupFactory('router:main'); + }, + + /** + Automatically initialize the application once the DOM has + become ready. + + The initialization itself is scheduled on the actions queue + which ensures that application loading finishes before + booting. + + If you are asynchronously loading code, you should call + `deferReadiness()` to defer booting, and then call + `advanceReadiness()` once all of your code has finished + loading. + + @private + @method scheduleInitialize + */ + scheduleInitialize: function() { + var self = this; + + if (!this.$ || this.$.isReady) { + run.schedule('actions', self, '_initialize'); + } else { + this.$().ready(function runInitialize() { + run(self, '_initialize'); + }); + } + }, + + /** + Use this to defer readiness until some condition is true. + + Example: + + ```javascript + App = Ember.Application.create(); + App.deferReadiness(); + + jQuery.getJSON("/auth-token", function(token) { + App.token = token; + App.advanceReadiness(); + }); + ``` + + This allows you to perform asynchronous setup logic and defer + booting your application until the setup has finished. + + However, if the setup requires a loading UI, it might be better + to use the router for this purpose. + + @method deferReadiness + */ + deferReadiness: function() { + this._readinessDeferrals++; + }, + + /** + Call `advanceReadiness` after any asynchronous setup logic has completed. + Each call to `deferReadiness` must be matched by a call to `advanceReadiness` + or the application will never become ready and routing will not begin. + + @method advanceReadiness + @see {Ember.Application#deferReadiness} + */ + advanceReadiness: function() { + this._readinessDeferrals--; + + if (this._readinessDeferrals === 0) { + run.once(this, this.didBecomeReady); + } + }, + + /** + Registers a factory that can be used for dependency injection (with + `App.inject`) or for service lookup. Each factory is registered with + a full name including two parts: `type:name`. + + A simple example: + + ```javascript + var App = Ember.Application.create(); + App.Orange = Ember.Object.extend(); + App.register('fruit:favorite', App.Orange); + ``` + + Ember will resolve factories from the `App` namespace automatically. + For example `App.CarsController` will be discovered and returned if + an application requests `controller:cars`. + + An example of registering a controller with a non-standard name: + + ```javascript + var App = Ember.Application.create(), + Session = Ember.Controller.extend(); + + App.register('controller:session', Session); + + // The Session controller can now be treated like a normal controller, + // despite its non-standard name. + App.ApplicationController = Ember.Controller.extend({ + needs: ['session'] + }); + ``` + + Registered factories are **instantiated** by having `create` + called on them. Additionally they are **singletons**, each time + they are looked up they return the same instance. + + Some examples modifying that default behavior: + + ```javascript + var App = Ember.Application.create(); + + App.Person = Ember.Object.extend(); + App.Orange = Ember.Object.extend(); + App.Email = Ember.Object.extend(); + App.session = Ember.Object.create(); + + App.register('model:user', App.Person, {singleton: false }); + App.register('fruit:favorite', App.Orange); + App.register('communication:main', App.Email, {singleton: false}); + App.register('session', App.session, {instantiate: false}); + ``` + + @method register + @param fullName {String} type:name (e.g., 'model:user') + @param factory {Function} (e.g., App.Person) + @param options {Object} (optional) disable instantiation or singleton usage + **/ + register: function() { + var container = this.__container__; + container.register.apply(container, arguments); + }, + + /** + Define a dependency injection onto a specific factory or all factories + of a type. + + When Ember instantiates a controller, view, or other framework component + it can attach a dependency to that component. This is often used to + provide services to a set of framework components. + + An example of providing a session object to all controllers: + + ```javascript + var App = Ember.Application.create(), + Session = Ember.Object.extend({ isAuthenticated: false }); + + // A factory must be registered before it can be injected + App.register('session:main', Session); + + // Inject 'session:main' onto all factories of the type 'controller' + // with the name 'session' + App.inject('controller', 'session', 'session:main'); + + App.IndexController = Ember.Controller.extend({ + isLoggedIn: Ember.computed.alias('session.isAuthenticated') + }); + ``` + + Injections can also be performed on specific factories. + + ```javascript + App.inject(, , ) + App.inject('route', 'source', 'source:main') + App.inject('route:application', 'email', 'model:email') + ``` + + It is important to note that injections can only be performed on + classes that are instantiated by Ember itself. Instantiating a class + directly (via `create` or `new`) bypasses the dependency injection + system. + + Ember-Data instantiates its models in a unique manner, and consequently + injections onto models (or all models) will not work as expected. Injections + on models can be enabled by setting `Ember.MODEL_FACTORY_INJECTIONS` + to `true`. + + @method inject + @param factoryNameOrType {String} + @param property {String} + @param injectionName {String} + **/ + inject: function() { + var container = this.__container__; + container.injection.apply(container, arguments); + }, + + /** + Calling initialize manually is not supported. + + Please see Ember.Application#advanceReadiness and + Ember.Application#deferReadiness. + + @private + @deprecated + @method initialize + **/ + initialize: function() { + }, + + /** + Initialize the application. This happens automatically. + + Run any initializers and run the application load hook. These hooks may + choose to defer readiness. For example, an authentication hook might want + to defer readiness until the auth token has been retrieved. + + @private + @method _initialize + */ + _initialize: function() { + if (this.isDestroyed) { return; } + + // At this point, the App.Router must already be assigned + if (this.Router) { + var container = this.__container__; + container.unregister('router:main'); + container.register('router:main', this.Router); + } + + this.runInitializers(); + runLoadHooks('application', this); + + // At this point, any initializers or load hooks that would have wanted + // to defer readiness have fired. In general, advancing readiness here + // will proceed to didBecomeReady. + this.advanceReadiness(); + + return this; + }, + + /** + Reset the application. This is typically used only in tests. It cleans up + the application in the following order: + + 1. Deactivate existing routes + 2. Destroy all objects in the container + 3. Create a new application container + 4. Re-route to the existing url + + Typical Example: + + ```javascript + + var App; + + run(function() { + App = Ember.Application.create(); + }); + + module("acceptance test", { + setup: function() { + App.reset(); + } + }); + + test("first test", function() { + // App is freshly reset + }); + + test("first test", function() { + // App is again freshly reset + }); + ``` + + Advanced Example: + + Occasionally you may want to prevent the app from initializing during + setup. This could enable extra configuration, or enable asserting prior + to the app becoming ready. + + ```javascript + + var App; + + run(function() { + App = Ember.Application.create(); + }); + + module("acceptance test", { + setup: function() { + run(function() { + App.reset(); + App.deferReadiness(); + }); + } + }); + + test("first test", function() { + ok(true, 'something before app is initialized'); + + run(function() { + App.advanceReadiness(); + }); + ok(true, 'something after app is initialized'); + }); + ``` + + @method reset + **/ + reset: function() { + this._readinessDeferrals = 1; + + function handleReset() { + var router = this.__container__.lookup('router:main'); + router.reset(); + + run(this.__container__, 'destroy'); + + this.buildContainer(); + + run.schedule('actions', this, function() { + this._initialize(); + }); + } + + run.join(this, handleReset); + }, + + /** + @private + @method runInitializers + */ + runInitializers: function() { + var initializersByName = get(this.constructor, 'initializers'); + var initializers = props(initializersByName); + var container = this.__container__; + var graph = new DAG(); + var namespace = this; + var name, initializer; + + for (var i = 0; i < initializers.length; i++) { + initializer = initializersByName[initializers[i]]; + graph.addEdges(initializer.name, initializer.initialize, initializer.before, initializer.after); + } + + graph.topsort(function (vertex) { + var initializer = vertex.value; + initializer(container, namespace); + }); + }, + + /** + @private + @method didBecomeReady + */ + didBecomeReady: function() { + this.setupEventDispatcher(); + this.ready(); // user hook + this.startRouting(); + + if (!Ember.testing) { + // Eagerly name all classes that are already loaded + Ember.Namespace.processAll(); + Ember.BOOTED = true; + } + + this.resolve(this); + }, + + /** + Setup up the event dispatcher to receive events on the + application's `rootElement` with any registered + `customEvents`. + + @private + @method setupEventDispatcher + */ + setupEventDispatcher: function() { + var customEvents = get(this, 'customEvents'); + var rootElement = get(this, 'rootElement'); + var dispatcher = this.__container__.lookup('event_dispatcher:main'); + + set(this, 'eventDispatcher', dispatcher); + dispatcher.setup(customEvents, rootElement); + }, + + /** + If the application has a router, use it to route to the current URL, and + trigger a new call to `route` whenever the URL changes. + + @private + @method startRouting + @property router {Ember.Router} + */ + startRouting: function() { + var router = this.__container__.lookup('router:main'); + if (!router) { return; } + + router.startRouting(); + }, + + handleURL: function(url) { + var router = this.__container__.lookup('router:main'); + + router.handleURL(url); + }, + + /** + Called when the Application has become ready. + The call will be delayed until the DOM has become ready. + + @event ready + */ + ready: K, + + /** + @deprecated Use 'Resolver' instead + Set this to provide an alternate class to `Ember.DefaultResolver` + + + @property resolver + */ + resolver: null, + + /** + Set this to provide an alternate class to `Ember.DefaultResolver` + + @property resolver + */ + Resolver: null, + + willDestroy: function() { + Ember.BOOTED = false; + // Ensure deactivation of routes before objects are destroyed + this.__container__.lookup('router:main').reset(); + + this.__container__.destroy(); + }, + + initializer: function(options) { + this.constructor.initializer(options); + }, + + /** + @method then + @private + @deprecated + */ + then: function() { + + this._super.apply(this, arguments); + } + }); + + Application.reopenClass({ + initializers: create(null), + + /** + Initializer receives an object which has the following attributes: + `name`, `before`, `after`, `initialize`. The only required attribute is + `initialize, all others are optional. + + * `name` allows you to specify under which name the initializer is registered. + This must be a unique name, as trying to register two initializers with the + same name will result in an error. + + ```javascript + Ember.Application.initializer({ + name: 'namedInitializer', + initialize: function(container, application) { + Ember.debug("Running namedInitializer!"); + } + }); + ``` + + * `before` and `after` are used to ensure that this initializer is ran prior + or after the one identified by the value. This value can be a single string + or an array of strings, referencing the `name` of other initializers. + + An example of ordering initializers, we create an initializer named `first`: + + ```javascript + Ember.Application.initializer({ + name: 'first', + initialize: function(container, application) { + Ember.debug("First initializer!"); + } + }); + + // DEBUG: First initializer! + ``` + + We add another initializer named `second`, specifying that it should run + after the initializer named `first`: + + ```javascript + Ember.Application.initializer({ + name: 'second', + after: 'first', + + initialize: function(container, application) { + Ember.debug("Second initializer!"); + } + }); + + // DEBUG: First initializer! + // DEBUG: Second initializer! + ``` + + Afterwards we add a further initializer named `pre`, this time specifying + that it should run before the initializer named `first`: + + ```javascript + Ember.Application.initializer({ + name: 'pre', + before: 'first', + + initialize: function(container, application) { + Ember.debug("Pre initializer!"); + } + }); + + // DEBUG: Pre initializer! + // DEBUG: First initializer! + // DEBUG: Second initializer! + ``` + + Finally we add an initializer named `post`, specifying it should run after + both the `first` and the `second` initializers: + + ```javascript + Ember.Application.initializer({ + name: 'post', + after: ['first', 'second'], + + initialize: function(container, application) { + Ember.debug("Post initializer!"); + } + }); + + // DEBUG: Pre initializer! + // DEBUG: First initializer! + // DEBUG: Second initializer! + // DEBUG: Post initializer! + ``` + + * `initialize` is a callback function that receives two arguments, `container` + and `application` on which you can operate. + + Example of using `container` to preload data into the store: + + ```javascript + Ember.Application.initializer({ + name: "preload-data", + + initialize: function(container, application) { + var store = container.lookup('store:main'); + store.pushPayload(preloadedData); + } + }); + ``` + + Example of using `application` to register an adapter: + + ```javascript + Ember.Application.initializer({ + name: 'api-adapter', + + initialize: function(container, application) { + application.register('api-adapter:main', ApiAdapter); + } + }); + ``` + + @method initializer + @param initializer {Object} + */ + initializer: function(initializer) { + // If this is the first initializer being added to a subclass, we are going to reopen the class + // to make sure we have a new `initializers` object, which extends from the parent class' using + // prototypal inheritance. Without this, attempting to add initializers to the subclass would + // pollute the parent class as well as other subclasses. + if (this.superclass.initializers !== undefined && this.superclass.initializers === this.initializers) { + this.reopenClass({ + initializers: create(this.initializers) + }); + } + + + this.initializers[initializer.name] = initializer; + }, + + /** + This creates a container with the default Ember naming conventions. + + It also configures the container: + + * registered views are created every time they are looked up (they are + not singletons) + * registered templates are not factories; the registered value is + returned directly. + * the router receives the application as its `namespace` property + * all controllers receive the router as their `target` and `controllers` + properties + * all controllers receive the application as their `namespace` property + * the application view receives the application controller as its + `controller` property + * the application view receives the application template as its + `defaultTemplate` property + + @private + @method buildContainer + @static + @param {Ember.Application} namespace the application to build the + container for. + @return {Ember.Container} the built container + */ + buildContainer: function(namespace) { + var container = new Container(); + + container.set = set; + container.resolver = resolverFor(namespace); + container.normalizeFullName = container.resolver.normalize; + container.describe = container.resolver.describe; + container.makeToString = container.resolver.makeToString; + + container.optionsForType('component', { singleton: false }); + container.optionsForType('view', { singleton: false }); + container.optionsForType('template', { instantiate: false }); + container.optionsForType('helper', { instantiate: false }); + + container.register('application:main', namespace, { instantiate: false }); + + container.register('controller:basic', Controller, { instantiate: false }); + container.register('controller:object', ObjectController, { instantiate: false }); + container.register('controller:array', ArrayController, { instantiate: false }); + + container.register('view:select', SelectView); + + container.register('route:basic', Route, { instantiate: false }); + container.register('event_dispatcher:main', EventDispatcher); + + container.register('router:main', Router); + container.injection('router:main', 'namespace', 'application:main'); + + container.register('location:auto', AutoLocation); + container.register('location:hash', HashLocation); + container.register('location:history', HistoryLocation); + container.register('location:none', NoneLocation); + + container.injection('controller', 'target', 'router:main'); + container.injection('controller', 'namespace', 'application:main'); + + container.register('-bucket-cache:main', BucketCache); + container.injection('router', '_bucketCache', '-bucket-cache:main'); + container.injection('route', '_bucketCache', '-bucket-cache:main'); + container.injection('controller', '_bucketCache', '-bucket-cache:main'); + + container.injection('route', 'router', 'router:main'); + container.injection('location', 'rootURL', '-location-setting:root-url'); + + // DEBUGGING + container.register('resolver-for-debugging:main', container.resolver.__resolver__, { instantiate: false }); + container.injection('container-debug-adapter:main', 'resolver', 'resolver-for-debugging:main'); + container.injection('data-adapter:main', 'containerDebugAdapter', 'container-debug-adapter:main'); + // Custom resolver authors may want to register their own ContainerDebugAdapter with this key + + // ES6TODO: resolve this via import once ember-application package is ES6'ed + if (!ContainerDebugAdapter) { ContainerDebugAdapter = requireModule('ember-extension-support/container_debug_adapter')['default']; } + container.register('container-debug-adapter:main', ContainerDebugAdapter); + + return container; + } + }); + + /** + This function defines the default lookup rules for container lookups: + + * templates are looked up on `Ember.TEMPLATES` + * other names are looked up on the application after classifying the name. + For example, `controller:post` looks up `App.PostController` by default. + * if the default lookup fails, look for registered classes on the container + + This allows the application to register default injections in the container + that could be overridden by the normal naming convention. + + @private + @method resolverFor + @param {Ember.Namespace} namespace the namespace to look for classes + @return {*} the resolved value for a given lookup + */ + function resolverFor(namespace) { + if (namespace.get('resolver')) { + } + + var ResolverClass = namespace.get('resolver') || namespace.get('Resolver') || DefaultResolver; + var resolver = ResolverClass.create({ + namespace: namespace + }); + + function resolve(fullName) { + return resolver.resolve(fullName); + } + + resolve.describe = function(fullName) { + return resolver.lookupDescription(fullName); + }; + + resolve.makeToString = function(factory, fullName) { + return resolver.makeToString(factory, fullName); + }; + + resolve.normalize = function(fullName) { + if (resolver.normalize) { + return resolver.normalize(fullName); + } else { + return fullName; + } + }; + + resolve.__resolver__ = resolver; + + return resolve; + } + + __exports__["default"] = Application; + }); +enifed("ember-application/system/dag", + ["ember-metal/error","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var EmberError = __dependency1__["default"]; + + function visit(vertex, fn, visited, path) { + var name = vertex.name; + var vertices = vertex.incoming; + var names = vertex.incomingNames; + var len = names.length; + var i; + + if (!visited) { + visited = {}; + } + if (!path) { + path = []; + } + if (visited.hasOwnProperty(name)) { + return; + } + path.push(name); + visited[name] = true; + for (i = 0; i < len; i++) { + visit(vertices[names[i]], fn, visited, path); + } + fn(vertex, path); + path.pop(); + } + + + /** + * DAG stands for Directed acyclic graph. + * + * It is used to build a graph of dependencies checking that there isn't circular + * dependencies. p.e Registering initializers with a certain precedence order. + * + * @class DAG + * @constructor + */ + function DAG() { + this.names = []; + this.vertices = Object.create(null); + } + + /** + * DAG Vertex + * + * @class Vertex + * @constructor + */ + + function Vertex(name) { + this.name = name; + this.incoming = {}; + this.incomingNames = []; + this.hasOutgoing = false; + this.value = null; + } + + /** + * Adds a vertex entry to the graph unless it is already added. + * + * @private + * @method add + * @param {String} name The name of the vertex to add + */ + DAG.prototype.add = function(name) { + if (!name) { + throw new Error("Can't add Vertex without name"); + } + if (this.vertices[name] !== undefined) { + return this.vertices[name]; + } + var vertex = new Vertex(name); + this.vertices[name] = vertex; + this.names.push(name); + return vertex; + }; + + /** + * Adds a vertex to the graph and sets its value. + * + * @private + * @method map + * @param {String} name The name of the vertex. + * @param value The value to put in the vertex. + */ + DAG.prototype.map = function(name, value) { + this.add(name).value = value; + }; + + /** + * Connects the vertices with the given names, adding them to the graph if + * necessary, only if this does not produce is any circular dependency. + * + * @private + * @method addEdge + * @param {String} fromName The name the vertex where the edge starts. + * @param {String} toName The name the vertex where the edge ends. + */ + DAG.prototype.addEdge = function(fromName, toName) { + if (!fromName || !toName || fromName === toName) { + return; + } + var from = this.add(fromName); + var to = this.add(toName); + if (to.incoming.hasOwnProperty(fromName)) { + return; + } + function checkCycle(vertex, path) { + if (vertex.name === toName) { + throw new EmberError("cycle detected: " + toName + " <- " + path.join(" <- ")); + } + } + visit(from, checkCycle); + from.hasOutgoing = true; + to.incoming[fromName] = from; + to.incomingNames.push(fromName); + }; + + /** + * Visits all the vertex of the graph calling the given function with each one, + * ensuring that the vertices are visited respecting their precedence. + * + * @method topsort + * @param {Function} fn The function to be invoked on each vertex. + */ + DAG.prototype.topsort = function(fn) { + var visited = {}; + var vertices = this.vertices; + var names = this.names; + var len = names.length; + var i, vertex; + + for (i = 0; i < len; i++) { + vertex = vertices[names[i]]; + if (!vertex.hasOutgoing) { + visit(vertex, fn, visited); + } + } + }; + + /** + * Adds a vertex with the given name and value to the graph and joins it with the + * vertices referenced in _before_ and _after_. If there isn't vertices with those + * names, they are added too. + * + * If either _before_ or _after_ are falsy/empty, the added vertex will not have + * an incoming/outgoing edge. + * + * @method addEdges + * @param {String} name The name of the vertex to be added. + * @param value The value of that vertex. + * @param before An string or array of strings with the names of the vertices before + * which this vertex must be visited. + * @param after An string or array of strings with the names of the vertex after + * which this vertex must be visited. + * + */ + DAG.prototype.addEdges = function(name, value, before, after) { + var i; + this.map(name, value); + if (before) { + if (typeof before === 'string') { + this.addEdge(name, before); + } else { + for (i = 0; i < before.length; i++) { + this.addEdge(name, before[i]); + } + } + } + if (after) { + if (typeof after === 'string') { + this.addEdge(after, name); + } else { + for (i = 0; i < after.length; i++) { + this.addEdge(after[i], name); + } + } + } + }; + + __exports__["default"] = DAG; + }); +enifed("ember-application/system/resolver", + ["ember-metal/core","ember-metal/property_get","ember-metal/logger","ember-runtime/system/string","ember-runtime/system/object","ember-runtime/system/namespace","ember-handlebars","ember-metal/dictionary","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-application + */ + + var Ember = __dependency1__["default"]; + // Ember.TEMPLATES, Ember.assert + var get = __dependency2__.get; + var Logger = __dependency3__["default"]; + var classify = __dependency4__.classify; + var capitalize = __dependency4__.capitalize; + var decamelize = __dependency4__.decamelize; + var EmberObject = __dependency5__["default"]; + var Namespace = __dependency6__["default"]; + var EmberHandlebars = __dependency7__["default"]; + + var Resolver = EmberObject.extend({ + /** + This will be set to the Application instance when it is + created. + + @property namespace + */ + namespace: null, + normalize: Ember.required(Function), + resolve: Ember.required(Function), + parseName: Ember.required(Function), + lookupDescription: Ember.required(Function), + makeToString: Ember.required(Function), + resolveOther: Ember.required(Function), + _logLookup: Ember.required(Function) + }); + __exports__.Resolver = Resolver; + /** + The DefaultResolver defines the default lookup rules to resolve + container lookups before consulting the container for registered + items: + + * templates are looked up on `Ember.TEMPLATES` + * other names are looked up on the application after converting + the name. For example, `controller:post` looks up + `App.PostController` by default. + * there are some nuances (see examples below) + + ### How Resolving Works + + The container calls this object's `resolve` method with the + `fullName` argument. + + It first parses the fullName into an object using `parseName`. + + Then it checks for the presence of a type-specific instance + method of the form `resolve[Type]` and calls it if it exists. + For example if it was resolving 'template:post', it would call + the `resolveTemplate` method. + + Its last resort is to call the `resolveOther` method. + + The methods of this object are designed to be easy to override + in a subclass. For example, you could enhance how a template + is resolved like so: + + ```javascript + App = Ember.Application.create({ + Resolver: Ember.DefaultResolver.extend({ + resolveTemplate: function(parsedName) { + var resolvedTemplate = this._super(parsedName); + if (resolvedTemplate) { return resolvedTemplate; } + return Ember.TEMPLATES['not_found']; + } + }) + }); + ``` + + Some examples of how names are resolved: + + ``` + 'template:post' //=> Ember.TEMPLATES['post'] + 'template:posts/byline' //=> Ember.TEMPLATES['posts/byline'] + 'template:posts.byline' //=> Ember.TEMPLATES['posts/byline'] + 'template:blogPost' //=> Ember.TEMPLATES['blogPost'] + // OR + // Ember.TEMPLATES['blog_post'] + 'controller:post' //=> App.PostController + 'controller:posts.index' //=> App.PostsIndexController + 'controller:blog/post' //=> Blog.PostController + 'controller:basic' //=> Ember.Controller + 'route:post' //=> App.PostRoute + 'route:posts.index' //=> App.PostsIndexRoute + 'route:blog/post' //=> Blog.PostRoute + 'route:basic' //=> Ember.Route + 'view:post' //=> App.PostView + 'view:posts.index' //=> App.PostsIndexView + 'view:blog/post' //=> Blog.PostView + 'view:basic' //=> Ember.View + 'foo:post' //=> App.PostFoo + 'model:post' //=> App.Post + ``` + + @class DefaultResolver + @namespace Ember + @extends Ember.Object + */ + var dictionary = __dependency8__["default"]; + + __exports__["default"] = EmberObject.extend({ + /** + This will be set to the Application instance when it is + created. + + @property namespace + */ + namespace: null, + + init: function() { + this._parseNameCache = dictionary(null); + }, + normalize: function(fullName) { + var split = fullName.split(':', 2); + var type = split[0]; + var name = split[1]; + + + if (type !== 'template') { + var result = name; + + if (result.indexOf('.') > -1) { + result = result.replace(/\.(.)/g, function(m) { + return m.charAt(1).toUpperCase(); + }); + } + + if (name.indexOf('_') > -1) { + result = result.replace(/_(.)/g, function(m) { + return m.charAt(1).toUpperCase(); + }); + } + + return type + ':' + result; + } else { + return fullName; + } + }, + + + /** + This method is called via the container's resolver method. + It parses the provided `fullName` and then looks up and + returns the appropriate template or class. + + @method resolve + @param {String} fullName the lookup string + @return {Object} the resolved factory + */ + resolve: function(fullName) { + var parsedName = this.parseName(fullName); + var resolveMethodName = parsedName.resolveMethodName; + var resolved; + + if (!(parsedName.name && parsedName.type)) { + throw new TypeError('Invalid fullName: `' + fullName + '`, must be of the form `type:name` '); + } + + if (this[resolveMethodName]) { + resolved = this[resolveMethodName](parsedName); + } + + if (!resolved) { + resolved = this.resolveOther(parsedName); + } + + if (parsedName.root && parsedName.root.LOG_RESOLVER) { + this._logLookup(resolved, parsedName); + } + + return resolved; + }, + /** + Convert the string name of the form 'type:name' to + a Javascript object with the parsed aspects of the name + broken out. + + @protected + @param {String} fullName the lookup string + @method parseName + */ + + parseName: function(fullName) { + return this._parseNameCache[fullName] || ( + this._parseNameCache[fullName] = this._parseName(fullName) + ); + }, + + _parseName: function(fullName) { + var nameParts = fullName.split(':'); + var type = nameParts[0], fullNameWithoutType = nameParts[1]; + var name = fullNameWithoutType; + var namespace = get(this, 'namespace'); + var root = namespace; + + if (type !== 'template' && name.indexOf('/') !== -1) { + var parts = name.split('/'); + name = parts[parts.length - 1]; + var namespaceName = capitalize(parts.slice(0, -1).join('.')); + root = Namespace.byName(namespaceName); + + } + + return { + fullName: fullName, + type: type, + fullNameWithoutType: fullNameWithoutType, + name: name, + root: root, + resolveMethodName: 'resolve' + classify(type) + }; + }, + + /** + Returns a human-readable description for a fullName. Used by the + Application namespace in assertions to describe the + precise name of the class that Ember is looking for, rather than + container keys. + + @protected + @param {String} fullName the lookup string + @method lookupDescription + */ + lookupDescription: function(fullName) { + var parsedName = this.parseName(fullName); + + if (parsedName.type === 'template') { + return 'template at ' + parsedName.fullNameWithoutType.replace(/\./g, '/'); + } + + var description = parsedName.root + '.' + classify(parsedName.name); + + if (parsedName.type !== 'model') { + description += classify(parsedName.type); + } + + return description; + }, + + makeToString: function(factory, fullName) { + return factory.toString(); + }, + /** + Given a parseName object (output from `parseName`), apply + the conventions expected by `Ember.Router` + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method useRouterNaming + */ + useRouterNaming: function(parsedName) { + parsedName.name = parsedName.name.replace(/\./g, '_'); + if (parsedName.name === 'basic') { + parsedName.name = ''; + } + }, + /** + Look up the template in Ember.TEMPLATES + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveTemplate + */ + resolveTemplate: function(parsedName) { + var templateName = parsedName.fullNameWithoutType.replace(/\./g, '/'); + + if (Ember.TEMPLATES[templateName]) { + return Ember.TEMPLATES[templateName]; + } + + templateName = decamelize(templateName); + if (Ember.TEMPLATES[templateName]) { + return Ember.TEMPLATES[templateName]; + } + }, + + /** + Lookup the view using `resolveOther` + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveView + */ + resolveView: function(parsedName) { + this.useRouterNaming(parsedName); + return this.resolveOther(parsedName); + }, + + /** + Lookup the controller using `resolveOther` + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveController + */ + resolveController: function(parsedName) { + this.useRouterNaming(parsedName); + return this.resolveOther(parsedName); + }, + /** + Lookup the route using `resolveOther` + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveRoute + */ + resolveRoute: function(parsedName) { + this.useRouterNaming(parsedName); + return this.resolveOther(parsedName); + }, + + /** + Lookup the model on the Application namespace + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveModel + */ + resolveModel: function(parsedName) { + var className = classify(parsedName.name); + var factory = get(parsedName.root, className); + + if (factory) { return factory; } + }, + /** + Look up the specified object (from parsedName) on the appropriate + namespace (usually on the Application) + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveHelper + */ + resolveHelper: function(parsedName) { + return this.resolveOther(parsedName) || EmberHandlebars.helpers[parsedName.fullNameWithoutType]; + }, + /** + Look up the specified object (from parsedName) on the appropriate + namespace (usually on the Application) + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveOther + */ + resolveOther: function(parsedName) { + var className = classify(parsedName.name) + classify(parsedName.type); + var factory = get(parsedName.root, className); + if (factory) { return factory; } + }, + + /** + @method _logLookup + @param {Boolean} found + @param {Object} parsedName + @private + */ + _logLookup: function(found, parsedName) { + var symbol, padding; + + if (found) { symbol = '[✓]'; } + else { symbol = '[ ]'; } + + if (parsedName.fullName.length > 60) { + padding = '.'; + } else { + padding = new Array(60 - parsedName.fullName.length).join('.'); + } + + Logger.info(symbol, parsedName.fullName, padding, this.lookupDescription(parsedName.fullName)); + } + }); + }); +enifed("ember-extension-support", + ["ember-metal/core","ember-extension-support/data_adapter","ember-extension-support/container_debug_adapter"], + function(__dependency1__, __dependency2__, __dependency3__) { + "use strict"; + /** + Ember Extension Support + + @module ember + @submodule ember-extension-support + @requires ember-application + */ + + var Ember = __dependency1__["default"]; + var DataAdapter = __dependency2__["default"]; + var ContainerDebugAdapter = __dependency3__["default"]; + + Ember.DataAdapter = DataAdapter; + Ember.ContainerDebugAdapter = ContainerDebugAdapter; + }); +enifed("ember-extension-support/container_debug_adapter", + ["ember-metal/core","ember-runtime/system/native_array","ember-metal/utils","ember-runtime/system/string","ember-runtime/system/namespace","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var emberA = __dependency2__.A; + var typeOf = __dependency3__.typeOf; + var dasherize = __dependency4__.dasherize; + var classify = __dependency4__.classify; + var Namespace = __dependency5__["default"]; + var EmberObject = __dependency6__["default"]; + + /** + @module ember + @submodule ember-extension-support + */ + + /** + The `ContainerDebugAdapter` helps the container and resolver interface + with tools that debug Ember such as the + [Ember Extension](https://github.com/tildeio/ember-extension) + for Chrome and Firefox. + + This class can be extended by a custom resolver implementer + to override some of the methods with library-specific code. + + The methods likely to be overridden are: + + * `canCatalogEntriesByType` + * `catalogEntriesByType` + + The adapter will need to be registered + in the application's container as `container-debug-adapter:main` + + Example: + + ```javascript + Application.initializer({ + name: "containerDebugAdapter", + + initialize: function(container, application) { + application.register('container-debug-adapter:main', require('app/container-debug-adapter')); + } + }); + ``` + + @class ContainerDebugAdapter + @namespace Ember + @extends EmberObject + @since 1.5.0 + */ + __exports__["default"] = EmberObject.extend({ + /** + The container of the application being debugged. + This property will be injected + on creation. + + @property container + @default null + */ + container: null, + + /** + The resolver instance of the application + being debugged. This property will be injected + on creation. + + @property resolver + @default null + */ + resolver: null, + + /** + Returns true if it is possible to catalog a list of available + classes in the resolver for a given type. + + @method canCatalogEntriesByType + @param {String} type The type. e.g. "model", "controller", "route" + @return {boolean} whether a list is available for this type. + */ + canCatalogEntriesByType: function(type) { + if (type === 'model' || type === 'template') return false; + return true; + }, + + /** + Returns the available classes a given type. + + @method catalogEntriesByType + @param {String} type The type. e.g. "model", "controller", "route" + @return {Array} An array of strings. + */ + catalogEntriesByType: function(type) { + var namespaces = emberA(Namespace.NAMESPACES), types = emberA(), self = this; + var typeSuffixRegex = new RegExp(classify(type) + "$"); + + namespaces.forEach(function(namespace) { + if (namespace !== Ember) { + for (var key in namespace) { + if (!namespace.hasOwnProperty(key)) { continue; } + if (typeSuffixRegex.test(key)) { + var klass = namespace[key]; + if (typeOf(klass) === 'class') { + types.push(dasherize(key.replace(typeSuffixRegex, ''))); + } + } + } + } + }); + return types; + } + }); + }); +enifed("ember-extension-support/data_adapter", + ["ember-metal/core","ember-metal/property_get","ember-metal/run_loop","ember-runtime/system/string","ember-runtime/system/namespace","ember-runtime/system/object","ember-runtime/system/native_array","ember-application/system/application","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var get = __dependency2__.get; + var run = __dependency3__["default"]; + var dasherize = __dependency4__.dasherize; + var Namespace = __dependency5__["default"]; + var EmberObject = __dependency6__["default"]; + var emberA = __dependency7__.A; + var Application = __dependency8__["default"]; + + /** + @module ember + @submodule ember-extension-support + */ + + /** + The `DataAdapter` helps a data persistence library + interface with tools that debug Ember such + as the [Ember Extension](https://github.com/tildeio/ember-extension) + for Chrome and Firefox. + + This class will be extended by a persistence library + which will override some of the methods with + library-specific code. + + The methods likely to be overridden are: + + * `getFilters` + * `detect` + * `columnsForType` + * `getRecords` + * `getRecordColumnValues` + * `getRecordKeywords` + * `getRecordFilterValues` + * `getRecordColor` + * `observeRecord` + + The adapter will need to be registered + in the application's container as `dataAdapter:main` + + Example: + + ```javascript + Application.initializer({ + name: "data-adapter", + + initialize: function(container, application) { + application.register('data-adapter:main', DS.DataAdapter); + } + }); + ``` + + @class DataAdapter + @namespace Ember + @extends EmberObject + */ + __exports__["default"] = EmberObject.extend({ + init: function() { + this._super(); + this.releaseMethods = emberA(); + }, + + /** + The container of the application being debugged. + This property will be injected + on creation. + + @property container + @default null + @since 1.3.0 + */ + container: null, + + + /** + The container-debug-adapter which is used + to list all models. + + @property containerDebugAdapter + @default undefined + @since 1.5.0 + **/ + containerDebugAdapter: undefined, + + /** + Number of attributes to send + as columns. (Enough to make the record + identifiable). + + @private + @property attributeLimit + @default 3 + @since 1.3.0 + */ + attributeLimit: 3, + + /** + Stores all methods that clear observers. + These methods will be called on destruction. + + @private + @property releaseMethods + @since 1.3.0 + */ + releaseMethods: emberA(), + + /** + Specifies how records can be filtered. + Records returned will need to have a `filterValues` + property with a key for every name in the returned array. + + @public + @method getFilters + @return {Array} List of objects defining filters. + The object should have a `name` and `desc` property. + */ + getFilters: function() { + return emberA(); + }, + + /** + Fetch the model types and observe them for changes. + + @public + @method watchModelTypes + + @param {Function} typesAdded Callback to call to add types. + Takes an array of objects containing wrapped types (returned from `wrapModelType`). + + @param {Function} typesUpdated Callback to call when a type has changed. + Takes an array of objects containing wrapped types. + + @return {Function} Method to call to remove all observers + */ + watchModelTypes: function(typesAdded, typesUpdated) { + var modelTypes = this.getModelTypes(); + var self = this; + var releaseMethods = emberA(); + var typesToSend; + + typesToSend = modelTypes.map(function(type) { + var klass = type.klass; + var wrapped = self.wrapModelType(klass, type.name); + releaseMethods.push(self.observeModelType(klass, typesUpdated)); + return wrapped; + }); + + typesAdded(typesToSend); + + var release = function() { + releaseMethods.forEach(function(fn) { fn(); }); + self.releaseMethods.removeObject(release); + }; + this.releaseMethods.pushObject(release); + return release; + }, + + _nameToClass: function(type) { + if (typeof type === 'string') { + type = this.container.lookupFactory('model:' + type); + } + return type; + }, + + /** + Fetch the records of a given type and observe them for changes. + + @public + @method watchRecords + + @param {Function} recordsAdded Callback to call to add records. + Takes an array of objects containing wrapped records. + The object should have the following properties: + columnValues: {Object} key and value of a table cell + object: {Object} the actual record object + + @param {Function} recordsUpdated Callback to call when a record has changed. + Takes an array of objects containing wrapped records. + + @param {Function} recordsRemoved Callback to call when a record has removed. + Takes the following parameters: + index: the array index where the records were removed + count: the number of records removed + + @return {Function} Method to call to remove all observers + */ + watchRecords: function(type, recordsAdded, recordsUpdated, recordsRemoved) { + var self = this, releaseMethods = emberA(), records = this.getRecords(type), release; + + var recordUpdated = function(updatedRecord) { + recordsUpdated([updatedRecord]); + }; + + var recordsToSend = records.map(function(record) { + releaseMethods.push(self.observeRecord(record, recordUpdated)); + return self.wrapRecord(record); + }); + + + var contentDidChange = function(array, idx, removedCount, addedCount) { + for (var i = idx; i < idx + addedCount; i++) { + var record = array.objectAt(i); + var wrapped = self.wrapRecord(record); + releaseMethods.push(self.observeRecord(record, recordUpdated)); + recordsAdded([wrapped]); + } + + if (removedCount) { + recordsRemoved(idx, removedCount); + } + }; + + var observer = { didChange: contentDidChange, willChange: Ember.K }; + records.addArrayObserver(self, observer); + + release = function() { + releaseMethods.forEach(function(fn) { fn(); }); + records.removeArrayObserver(self, observer); + self.releaseMethods.removeObject(release); + }; + + recordsAdded(recordsToSend); + + this.releaseMethods.pushObject(release); + return release; + }, + + /** + Clear all observers before destruction + @private + @method willDestroy + */ + willDestroy: function() { + this._super(); + this.releaseMethods.forEach(function(fn) { + fn(); + }); + }, + + /** + Detect whether a class is a model. + + Test that against the model class + of your persistence library + + @private + @method detect + @param {Class} klass The class to test + @return boolean Whether the class is a model class or not + */ + detect: function(klass) { + return false; + }, + + /** + Get the columns for a given model type. + + @private + @method columnsForType + @param {Class} type The model type + @return {Array} An array of columns of the following format: + name: {String} name of the column + desc: {String} Humanized description (what would show in a table column name) + */ + columnsForType: function(type) { + return emberA(); + }, + + /** + Adds observers to a model type class. + + @private + @method observeModelType + @param {Class} type The model type class + @param {Function} typesUpdated Called when a type is modified. + @return {Function} The function to call to remove observers + */ + + observeModelType: function(type, typesUpdated) { + var self = this; + var records = this.getRecords(type); + + var onChange = function() { + typesUpdated([self.wrapModelType(type)]); + }; + var observer = { + didChange: function() { + run.scheduleOnce('actions', this, onChange); + }, + willChange: Ember.K + }; + + records.addArrayObserver(this, observer); + + var release = function() { + records.removeArrayObserver(self, observer); + }; + + return release; + }, + + + /** + Wraps a given model type and observes changes to it. + + @private + @method wrapModelType + @param {Class} type A model class + @param {String} Optional name of the class + @return {Object} contains the wrapped type and the function to remove observers + Format: + type: {Object} the wrapped type + The wrapped type has the following format: + name: {String} name of the type + count: {Integer} number of records available + columns: {Columns} array of columns to describe the record + object: {Class} the actual Model type class + release: {Function} The function to remove observers + */ + wrapModelType: function(type, name) { + var records = this.getRecords(type); + var self = this; + var release, typeToSend; + + typeToSend = { + name: name || type.toString(), + count: get(records, 'length'), + columns: this.columnsForType(type), + object: type + }; + + + return typeToSend; + }, + + + /** + Fetches all models defined in the application. + + @private + @method getModelTypes + @return {Array} Array of model types + */ + getModelTypes: function() { + var self = this; + var containerDebugAdapter = this.get('containerDebugAdapter'); + var types; + + if (containerDebugAdapter.canCatalogEntriesByType('model')) { + types = containerDebugAdapter.catalogEntriesByType('model'); + } else { + types = this._getObjectsOnNamespaces(); + } + + // New adapters return strings instead of classes + types = emberA(types).map(function(name) { + return { + klass: self._nameToClass(name), + name: name + }; + }); + types = emberA(types).filter(function(type) { + return self.detect(type.klass); + }); + + return emberA(types); + }, + + /** + Loops over all namespaces and all objects + attached to them + + @private + @method _getObjectsOnNamespaces + @return {Array} Array of model type strings + */ + _getObjectsOnNamespaces: function() { + var namespaces = emberA(Namespace.NAMESPACES); + var types = emberA(); + var self = this; + + namespaces.forEach(function(namespace) { + for (var key in namespace) { + if (!namespace.hasOwnProperty(key)) { continue; } + // Even though we will filter again in `getModelTypes`, + // we should not call `lookupContainer` on non-models + // (especially when `Ember.MODEL_FACTORY_INJECTIONS` is `true`) + if (!self.detect(namespace[key])) { continue; } + var name = dasherize(key); + if (!(namespace instanceof Application) && namespace.toString()) { + name = namespace + '/' + name; + } + types.push(name); + } + }); + return types; + }, + + /** + Fetches all loaded records for a given type. + + @private + @method getRecords + @return {Array} An array of records. + This array will be observed for changes, + so it should update when new records are added/removed. + */ + getRecords: function(type) { + return emberA(); + }, + + /** + Wraps a record and observers changes to it. + + @private + @method wrapRecord + @param {Object} record The record instance. + @return {Object} The wrapped record. Format: + columnValues: {Array} + searchKeywords: {Array} + */ + wrapRecord: function(record) { + var recordToSend = { object: record }; + var columnValues = {}; + var self = this; + + recordToSend.columnValues = this.getRecordColumnValues(record); + recordToSend.searchKeywords = this.getRecordKeywords(record); + recordToSend.filterValues = this.getRecordFilterValues(record); + recordToSend.color = this.getRecordColor(record); + + return recordToSend; + }, + + /** + Gets the values for each column. + + @private + @method getRecordColumnValues + @return {Object} Keys should match column names defined + by the model type. + */ + getRecordColumnValues: function(record) { + return {}; + }, + + /** + Returns keywords to match when searching records. + + @private + @method getRecordKeywords + @return {Array} Relevant keywords for search. + */ + getRecordKeywords: function(record) { + return emberA(); + }, + + /** + Returns the values of filters defined by `getFilters`. + + @private + @method getRecordFilterValues + @param {Object} record The record instance + @return {Object} The filter values + */ + getRecordFilterValues: function(record) { + return {}; + }, + + /** + Each record can have a color that represents its state. + + @private + @method getRecordColor + @param {Object} record The record instance + @return {String} The record's color + Possible options: black, red, blue, green + */ + getRecordColor: function(record) { + return null; + }, + + /** + Observes all relevant properties and re-sends the wrapped record + when a change occurs. + + @private + @method observerRecord + @param {Object} record The record instance + @param {Function} recordUpdated The callback to call when a record is updated. + @return {Function} The function to call to remove all observers. + */ + observeRecord: function(record, recordUpdated) { + return function(){}; + } + }); + }); +enifed("ember-extension-support/initializers", + [], + function() { + "use strict"; + + }); +enifed("ember-handlebars-compiler", + ["ember-metal/core","exports"], + function(__dependency1__, __exports__) { + /* global Handlebars:true */ + + // Remove "use strict"; from transpiled module (in browser builds only) until + // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed + // + // REMOVE_USE_STRICT: true + + /** + @module ember + @submodule ember-handlebars-compiler + */ + + var Ember = __dependency1__["default"]; + + // ES6Todo: you'll need to import debugger once debugger is es6'd. + if (typeof Ember.assert === 'undefined') { Ember.assert = function(){}; } + if (typeof Ember.FEATURES === 'undefined') { Ember.FEATURES = { isEnabled: function(){} }; } + + var objectCreate = Object.create || function(parent) { + function F() {} + F.prototype = parent; + return new F(); + }; + + // set up for circular references later + var View, Component; + + // ES6Todo: when ember-debug is es6'ed import this. + // var emberAssert = Ember.assert; + var Handlebars = (Ember.imports && Ember.imports.Handlebars) || (this && this.Handlebars); + if (!Handlebars && typeof eriuqer === 'function') { + Handlebars = eriuqer('handlebars'); + } + + + + /** + Prepares the Handlebars templating library for use inside Ember's view + system. + + The `Ember.Handlebars` object is the standard Handlebars library, extended to + use Ember's `get()` method instead of direct property access, which allows + computed properties to be used inside templates. + + To create an `Ember.Handlebars` template, call `Ember.Handlebars.compile()`. + This will return a function that can be used by `Ember.View` for rendering. + + @class Handlebars + @namespace Ember + */ + var EmberHandlebars = Ember.Handlebars = objectCreate(Handlebars); + + /** + Register a bound helper or custom view helper. + + ## Simple bound helper example + + ```javascript + Ember.Handlebars.helper('capitalize', function(value) { + return value.toUpperCase(); + }); + ``` + + The above bound helper can be used inside of templates as follows: + + ```handlebars + {{capitalize name}} + ``` + + In this case, when the `name` property of the template's context changes, + the rendered value of the helper will update to reflect this change. + + For more examples of bound helpers, see documentation for + `Ember.Handlebars.registerBoundHelper`. + + ## Custom view helper example + + Assuming a view subclass named `App.CalendarView` were defined, a helper + for rendering instances of this view could be registered as follows: + + ```javascript + Ember.Handlebars.helper('calendar', App.CalendarView): + ``` + + The above bound helper can be used inside of templates as follows: + + ```handlebars + {{calendar}} + ``` + + Which is functionally equivalent to: + + ```handlebars + {{view 'calendar'}} + ``` + + Options in the helper will be passed to the view in exactly the same + manner as with the `view` helper. + + @method helper + @for Ember.Handlebars + @param {String} name + @param {Function|Ember.View} function or view class constructor + @param {String} dependentKeys* + */ + EmberHandlebars.helper = function(name, value) { + if (!View) { View = requireModule('ember-views/views/view')['default']; } // ES6TODO: stupid circular dep + if (!Component) { Component = requireModule('ember-views/views/component')['default']; } // ES6TODO: stupid circular dep + + + if (View.detect(value)) { + EmberHandlebars.registerHelper(name, EmberHandlebars.makeViewHelper(value)); + } else { + EmberHandlebars.registerBoundHelper.apply(null, arguments); + } + }; + + /** + Returns a helper function that renders the provided ViewClass. + + Used internally by Ember.Handlebars.helper and other methods + involving helper/component registration. + + @private + @method makeViewHelper + @for Ember.Handlebars + @param {Function} ViewClass view class constructor + @since 1.2.0 + */ + EmberHandlebars.makeViewHelper = function(ViewClass) { + return function(options) { + return EmberHandlebars.helpers.view.call(this, ViewClass, options); + }; + }; + + /** + @class helpers + @namespace Ember.Handlebars + */ + EmberHandlebars.helpers = objectCreate(Handlebars.helpers); + + /** + Override the the opcode compiler and JavaScript compiler for Handlebars. + + @class Compiler + @namespace Ember.Handlebars + @private + @constructor + */ + EmberHandlebars.Compiler = function() {}; + + // Handlebars.Compiler doesn't exist in runtime-only + if (Handlebars.Compiler) { + EmberHandlebars.Compiler.prototype = objectCreate(Handlebars.Compiler.prototype); + } + + EmberHandlebars.Compiler.prototype.compiler = EmberHandlebars.Compiler; + + /** + @class JavaScriptCompiler + @namespace Ember.Handlebars + @private + @constructor + */ + EmberHandlebars.JavaScriptCompiler = function() {}; + + // Handlebars.JavaScriptCompiler doesn't exist in runtime-only + if (Handlebars.JavaScriptCompiler) { + EmberHandlebars.JavaScriptCompiler.prototype = objectCreate(Handlebars.JavaScriptCompiler.prototype); + EmberHandlebars.JavaScriptCompiler.prototype.compiler = EmberHandlebars.JavaScriptCompiler; + } + + + EmberHandlebars.JavaScriptCompiler.prototype.namespace = "Ember.Handlebars"; + + EmberHandlebars.JavaScriptCompiler.prototype.initializeBuffer = function() { + return "''"; + }; + + /** + Override the default buffer for Ember Handlebars. By default, Handlebars + creates an empty String at the beginning of each invocation and appends to + it. Ember's Handlebars overrides this to append to a single shared buffer. + + @private + @method appendToBuffer + @param string {String} + */ + EmberHandlebars.JavaScriptCompiler.prototype.appendToBuffer = function(string) { + return "data.buffer.push("+string+");"; + }; + + // Hacks ahead: + // Handlebars presently has a bug where the `blockHelperMissing` hook + // doesn't get passed the name of the missing helper name, but rather + // gets passed the value of that missing helper evaluated on the current + // context, which is most likely `undefined` and totally useless. + // + // So we alter the compiled template function to pass the name of the helper + // instead, as expected. + // + // This can go away once the following is closed: + // https://github.com/wycats/handlebars.js/issues/634 + + var DOT_LOOKUP_REGEX = /helpers\.(.*?)\)/; + var BRACKET_STRING_LOOKUP_REGEX = /helpers\['(.*?)'/; + var INVOCATION_SPLITTING_REGEX = /(.*blockHelperMissing\.call\(.*)(stack[0-9]+)(,.*)/; + + EmberHandlebars.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation = function(source) { + var helperInvocation = source[source.length - 1]; + var helperName = (DOT_LOOKUP_REGEX.exec(helperInvocation) || BRACKET_STRING_LOOKUP_REGEX.exec(helperInvocation))[1]; + var matches = INVOCATION_SPLITTING_REGEX.exec(helperInvocation); + + source[source.length - 1] = matches[1] + "'" + helperName + "'" + matches[3]; + }; + + var stringifyBlockHelperMissing = EmberHandlebars.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation; + + var originalBlockValue = EmberHandlebars.JavaScriptCompiler.prototype.blockValue; + EmberHandlebars.JavaScriptCompiler.prototype.blockValue = function() { + originalBlockValue.apply(this, arguments); + stringifyBlockHelperMissing(this.source); + }; + + var originalAmbiguousBlockValue = EmberHandlebars.JavaScriptCompiler.prototype.ambiguousBlockValue; + EmberHandlebars.JavaScriptCompiler.prototype.ambiguousBlockValue = function() { + originalAmbiguousBlockValue.apply(this, arguments); + stringifyBlockHelperMissing(this.source); + }; + + /** + Rewrite simple mustaches from `{{foo}}` to `{{bind "foo"}}`. This means that + all simple mustaches in Ember's Handlebars will also set up an observer to + keep the DOM up to date when the underlying property changes. + + @private + @method mustache + @for Ember.Handlebars.Compiler + @param mustache + */ + EmberHandlebars.Compiler.prototype.mustache = function(mustache) { + if (!(mustache.params.length || mustache.hash)) { + var id = new Handlebars.AST.IdNode([{ part: '_triageMustache' }]); + + // Update the mustache node to include a hash value indicating whether the original node + // was escaped. This will allow us to properly escape values when the underlying value + // changes and we need to re-render the value. + if (!mustache.escaped) { + mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]); + mustache.hash.pairs.push(["unescaped", new Handlebars.AST.StringNode("true")]); + } + mustache = new Handlebars.AST.MustacheNode([id].concat([mustache.id]), mustache.hash, !mustache.escaped); + } + + return Handlebars.Compiler.prototype.mustache.call(this, mustache); + }; + + /** + Used for precompilation of Ember Handlebars templates. This will not be used + during normal app execution. + + @method precompile + @for Ember.Handlebars + @static + @param {String|Object} value The template to precompile or an Handlebars AST + @param {Boolean} asObject optional parameter, defaulting to true, of whether or not the + compiled template should be returned as an Object or a String + */ + EmberHandlebars.precompile = function(value, asObject) { + var ast = Handlebars.parse(value); + + var options = { + knownHelpers: { + action: true, + unbound: true, + 'bind-attr': true, + template: true, + view: true, + _triageMustache: true + }, + data: true, + stringParams: true + }; + + asObject = asObject === undefined ? true : asObject; + + var environment = new EmberHandlebars.Compiler().compile(ast, options); + return new EmberHandlebars.JavaScriptCompiler().compile(environment, options, undefined, asObject); + }; + + // We don't support this for Handlebars runtime-only + if (Handlebars.compile) { + /** + The entry point for Ember Handlebars. This replaces the default + `Handlebars.compile` and turns on template-local data and String + parameters. + + @method compile + @for Ember.Handlebars + @static + @param {String} string The template to compile + @return {Function} + */ + EmberHandlebars.compile = function(string) { + var ast = Handlebars.parse(string); + var options = { data: true, stringParams: true }; + var environment = new EmberHandlebars.Compiler().compile(ast, options); + var templateSpec = new EmberHandlebars.JavaScriptCompiler().compile(environment, options, undefined, true); + + var template = EmberHandlebars.template(templateSpec); + template.isMethod = false; //Make sure we don't wrap templates with ._super + + return template; + }; + } + + __exports__["default"] = EmberHandlebars; + }); +enifed("ember-handlebars", + ["ember-handlebars-compiler","ember-metal/core","ember-runtime/system/lazy_load","ember-handlebars/loader","ember-handlebars/ext","ember-handlebars/string","ember-handlebars/helpers/shared","ember-handlebars/helpers/binding","ember-handlebars/helpers/collection","ember-handlebars/helpers/view","ember-handlebars/helpers/unbound","ember-handlebars/helpers/debug","ember-handlebars/helpers/each","ember-handlebars/helpers/template","ember-handlebars/helpers/partial","ember-handlebars/helpers/yield","ember-handlebars/helpers/loc","ember-handlebars/controls/checkbox","ember-handlebars/controls/select","ember-handlebars/controls/text_area","ember-handlebars/controls/text_field","ember-handlebars/controls/text_support","ember-handlebars/controls","ember-handlebars/component_lookup","ember-handlebars/views/handlebars_bound_view","ember-handlebars/views/metamorph_view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __dependency18__, __dependency19__, __dependency20__, __dependency21__, __dependency22__, __dependency23__, __dependency24__, __dependency25__, __dependency26__, __exports__) { + "use strict"; + var EmberHandlebars = __dependency1__["default"]; + var Ember = __dependency2__["default"]; + // to add to globals + + var runLoadHooks = __dependency3__.runLoadHooks; + var bootstrap = __dependency4__["default"]; + + var normalizePath = __dependency5__.normalizePath; + var template = __dependency5__.template; + var makeBoundHelper = __dependency5__.makeBoundHelper; + var registerBoundHelper = __dependency5__.registerBoundHelper; + var resolveHash = __dependency5__.resolveHash; + var resolveParams = __dependency5__.resolveParams; + var getEscaped = __dependency5__.getEscaped; + var handlebarsGet = __dependency5__.handlebarsGet; + var evaluateUnboundHelper = __dependency5__.evaluateUnboundHelper; + var helperMissingHelper = __dependency5__.helperMissingHelper; + var blockHelperMissingHelper = __dependency5__.blockHelperMissingHelper; + + + // side effect of extending StringUtils of htmlSafe + + var resolvePaths = __dependency7__["default"]; + var bind = __dependency8__.bind; + var _triageMustacheHelper = __dependency8__._triageMustacheHelper; + var resolveHelper = __dependency8__.resolveHelper; + var bindHelper = __dependency8__.bindHelper; + var boundIfHelper = __dependency8__.boundIfHelper; + var unboundIfHelper = __dependency8__.unboundIfHelper; + var withHelper = __dependency8__.withHelper; + var ifHelper = __dependency8__.ifHelper; + var unlessHelper = __dependency8__.unlessHelper; + var bindAttrHelper = __dependency8__.bindAttrHelper; + var bindAttrHelperDeprecated = __dependency8__.bindAttrHelperDeprecated; + var bindClasses = __dependency8__.bindClasses; + + var collectionHelper = __dependency9__["default"]; + var ViewHelper = __dependency10__.ViewHelper; + var viewHelper = __dependency10__.viewHelper; + var unboundHelper = __dependency11__["default"]; + var logHelper = __dependency12__.logHelper; + var debuggerHelper = __dependency12__.debuggerHelper; + var EachView = __dependency13__.EachView; + var GroupedEach = __dependency13__.GroupedEach; + var eachHelper = __dependency13__.eachHelper; + var templateHelper = __dependency14__["default"]; + var partialHelper = __dependency15__["default"]; + var yieldHelper = __dependency16__["default"]; + var locHelper = __dependency17__["default"]; + + + var Checkbox = __dependency18__["default"]; + var Select = __dependency19__.Select; + var SelectOption = __dependency19__.SelectOption; + var SelectOptgroup = __dependency19__.SelectOptgroup; + var TextArea = __dependency20__["default"]; + var TextField = __dependency21__["default"]; + var TextSupport = __dependency22__["default"]; + var inputHelper = __dependency23__.inputHelper; + var textareaHelper = __dependency23__.textareaHelper; + + + var ComponentLookup = __dependency24__["default"]; + var _HandlebarsBoundView = __dependency25__._HandlebarsBoundView; + var SimpleHandlebarsView = __dependency25__.SimpleHandlebarsView; + var _wrapMap = __dependency26__._wrapMap; + var _SimpleMetamorphView = __dependency26__._SimpleMetamorphView; + var _MetamorphView = __dependency26__._MetamorphView; + var _Metamorph = __dependency26__._Metamorph; + + + /** + Ember Handlebars + + @module ember + @submodule ember-handlebars + @requires ember-views + */ + + // Ember.Handlebars.Globals + EmberHandlebars.bootstrap = bootstrap; + EmberHandlebars.template = template; + EmberHandlebars.makeBoundHelper = makeBoundHelper; + EmberHandlebars.registerBoundHelper = registerBoundHelper; + EmberHandlebars.resolveHash = resolveHash; + EmberHandlebars.resolveParams = resolveParams; + EmberHandlebars.resolveHelper = resolveHelper; + EmberHandlebars.get = handlebarsGet; + EmberHandlebars.getEscaped = getEscaped; + EmberHandlebars.evaluateUnboundHelper = evaluateUnboundHelper; + EmberHandlebars.bind = bind; + EmberHandlebars.bindClasses = bindClasses; + EmberHandlebars.EachView = EachView; + EmberHandlebars.GroupedEach = GroupedEach; + EmberHandlebars.resolvePaths = resolvePaths; + EmberHandlebars.ViewHelper = ViewHelper; + EmberHandlebars.normalizePath = normalizePath; + + + // Ember Globals + Ember.Handlebars = EmberHandlebars; + Ember.ComponentLookup = ComponentLookup; + Ember._SimpleHandlebarsView = SimpleHandlebarsView; + Ember._HandlebarsBoundView = _HandlebarsBoundView; + Ember._SimpleMetamorphView = _SimpleMetamorphView; + Ember._MetamorphView = _MetamorphView; + Ember._Metamorph = _Metamorph; + Ember._metamorphWrapMap = _wrapMap; + Ember.TextSupport = TextSupport; + Ember.Checkbox = Checkbox; + Ember.Select = Select; + Ember.SelectOption = SelectOption; + Ember.SelectOptgroup = SelectOptgroup; + Ember.TextArea = TextArea; + Ember.TextField = TextField; + Ember.TextSupport = TextSupport; + + // register helpers + EmberHandlebars.registerHelper('helperMissing', helperMissingHelper); + EmberHandlebars.registerHelper('blockHelperMissing', blockHelperMissingHelper); + EmberHandlebars.registerHelper('bind', bindHelper); + EmberHandlebars.registerHelper('boundIf', boundIfHelper); + EmberHandlebars.registerHelper('_triageMustache', _triageMustacheHelper); + EmberHandlebars.registerHelper('unboundIf', unboundIfHelper); + EmberHandlebars.registerHelper('with', withHelper); + EmberHandlebars.registerHelper('if', ifHelper); + EmberHandlebars.registerHelper('unless', unlessHelper); + EmberHandlebars.registerHelper('bind-attr', bindAttrHelper); + EmberHandlebars.registerHelper('bindAttr', bindAttrHelperDeprecated); + EmberHandlebars.registerHelper('collection', collectionHelper); + EmberHandlebars.registerHelper("log", logHelper); + EmberHandlebars.registerHelper("debugger", debuggerHelper); + EmberHandlebars.registerHelper("each", eachHelper); + EmberHandlebars.registerHelper("loc", locHelper); + EmberHandlebars.registerHelper("partial", partialHelper); + EmberHandlebars.registerHelper("template", templateHelper); + EmberHandlebars.registerHelper("yield", yieldHelper); + EmberHandlebars.registerHelper("view", viewHelper); + EmberHandlebars.registerHelper("unbound", unboundHelper); + EmberHandlebars.registerHelper("input", inputHelper); + EmberHandlebars.registerHelper("textarea", textareaHelper); + + // run load hooks + runLoadHooks('Ember.Handlebars', EmberHandlebars); + + __exports__["default"] = EmberHandlebars; + }); +enifed("ember-handlebars/component_lookup", + ["ember-runtime/system/object","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var EmberObject = __dependency1__["default"]; + + var ComponentLookup = EmberObject.extend({ + lookupFactory: function(name, container) { + + container = container || this.container; + + var fullName = 'component:' + name; + var templateFullName = 'template:components/' + name; + var templateRegistered = container && container.has(templateFullName); + + if (templateRegistered) { + container.injection(fullName, 'layout', templateFullName); + } + + var Component = container.lookupFactory(fullName); + + // Only treat as a component if either the component + // or a template has been registered. + if (templateRegistered || Component) { + if (!Component) { + container.register(fullName, Ember.Component); + Component = container.lookupFactory(fullName); + } + return Component; + } + } + }); + + __exports__["default"] = ComponentLookup; + }); +enifed("ember-handlebars/controls", + ["ember-handlebars/controls/checkbox","ember-handlebars/controls/text_field","ember-handlebars/controls/text_area","ember-metal/core","ember-handlebars-compiler","ember-handlebars/ext","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + var Checkbox = __dependency1__["default"]; + var TextField = __dependency2__["default"]; + var TextArea = __dependency3__["default"]; + + var Ember = __dependency4__["default"]; + // Ember.assert + // var emberAssert = Ember.assert; + + var EmberHandlebars = __dependency5__["default"]; + var handlebarsGet = __dependency6__.handlebarsGet; + var helpers = EmberHandlebars.helpers; + /** + @module ember + @submodule ember-handlebars-compiler + */ + + function _resolveOption(context, options, key) { + if (options.hashTypes[key] === "ID") { + return handlebarsGet(context, options.hash[key], options); + } else { + return options.hash[key]; + } + } + + /** + + The `{{input}}` helper inserts an HTML `` tag into the template, + with a `type` value of either `text` or `checkbox`. If no `type` is provided, + `text` will be the default value applied. The attributes of `{{input}}` + match those of the native HTML tag as closely as possible for these two types. + + ## Use as text field + An `{{input}}` with no `type` or a `type` of `text` will render an HTML text input. + The following HTML attributes can be set via the helper: + +
    + + + + + + + + + + +
    `readonly``required``autofocus`
    `value``placeholder``disabled`
    `size``tabindex``maxlength`
    `name``min``max`
    `pattern``accept``autocomplete`
    `autosave``formaction``formenctype`
    `formmethod``formnovalidate``formtarget`
    `height``inputmode``multiple`
    `step``width``form`
    `selectionDirection``spellcheck` 
    + + + When set to a quoted string, these values will be directly applied to the HTML + element. When left unquoted, these values will be bound to a property on the + template's current rendering context (most typically a controller instance). + + ## Unbound: + + ```handlebars + {{input value="http://www.facebook.com"}} + ``` + + + ```html + + ``` + + ## Bound: + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + firstName: "Stanley", + entryNotAllowed: true + }); + ``` + + + ```handlebars + {{input type="text" value=firstName disabled=entryNotAllowed size="50"}} + ``` + + + ```html + + ``` + + ## Actions + + The helper can send multiple actions based on user events. + + The action property defines the action which is sent when + the user presses the return key. + + ```handlebars + {{input action="submit"}} + ``` + + The helper allows some user events to send actions. + + * `enter` + * `insert-newline` + * `escape-press` + * `focus-in` + * `focus-out` + * `key-press` + + + For example, if you desire an action to be sent when the input is blurred, + you only need to setup the action name to the event name property. + + ```handlebars + {{input focus-in="alertMessage"}} + ``` + + See more about [Text Support Actions](/api/classes/Ember.TextField.html) + + ## Extension + + Internally, `{{input type="text"}}` creates an instance of `Ember.TextField`, passing + arguments from the helper to `Ember.TextField`'s `create` method. You can extend the + capabilities of text inputs in your applications by reopening this class. For example, + if you are building a Bootstrap project where `data-*` attributes are used, you + can add one to the `TextField`'s `attributeBindings` property: + + + ```javascript + Ember.TextField.reopen({ + attributeBindings: ['data-error'] + }); + ``` + + Keep in mind when writing `Ember.TextField` subclasses that `Ember.TextField` + itself extends `Ember.Component`, meaning that it does NOT inherit + the `controller` of the parent view. + + See more about [Ember components](/api/classes/Ember.Component.html) + + + ## Use as checkbox + + An `{{input}}` with a `type` of `checkbox` will render an HTML checkbox input. + The following HTML attributes can be set via the helper: + + * `checked` + * `disabled` + * `tabindex` + * `indeterminate` + * `name` + * `autofocus` + * `form` + + + When set to a quoted string, these values will be directly applied to the HTML + element. When left unquoted, these values will be bound to a property on the + template's current rendering context (most typically a controller instance). + + ## Unbound: + + ```handlebars + {{input type="checkbox" name="isAdmin"}} + ``` + + ```html + + ``` + + ## Bound: + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + isAdmin: true + }); + ``` + + + ```handlebars + {{input type="checkbox" checked=isAdmin }} + ``` + + + ```html + + ``` + + ## Extension + + Internally, `{{input type="checkbox"}}` creates an instance of `Ember.Checkbox`, passing + arguments from the helper to `Ember.Checkbox`'s `create` method. You can extend the + capablilties of checkbox inputs in your applications by reopening this class. For example, + if you wanted to add a css class to all checkboxes in your application: + + + ```javascript + Ember.Checkbox.reopen({ + classNames: ['my-app-checkbox'] + }); + ``` + + + @method input + @for Ember.Handlebars.helpers + @param {Hash} options + */ + function inputHelper(options) { + + var hash = options.hash; + var types = options.hashTypes; + var inputType = _resolveOption(this, options, 'type'); + var onEvent = hash.on; + + if (inputType === 'checkbox') { + delete hash.type; + delete types.type; + + + return helpers.view.call(this, Checkbox, options); + } else { + delete hash.on; + + hash.onEvent = onEvent || 'enter'; + return helpers.view.call(this, TextField, options); + } + } + + __exports__.inputHelper = inputHelper;/** + `{{textarea}}` inserts a new instance of ` + ``` + + Bound: + + In the following example, the `writtenWords` property on `App.ApplicationController` + will be updated live as the user types 'Lots of text that IS bound' into + the text area of their browser's window. + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + writtenWords: "Lots of text that IS bound" + }); + ``` + + ```handlebars + {{textarea value=writtenWords}} + ``` + + Would result in the following HTML: + + ```html + + ``` + + If you wanted a one way binding between the text area and a div tag + somewhere else on your screen, you could use `Ember.computed.oneWay`: + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + writtenWords: "Lots of text that IS bound", + outputWrittenWords: Ember.computed.oneWay("writtenWords") + }); + ``` + + ```handlebars + {{textarea value=writtenWords}} + +
    + {{outputWrittenWords}} +
    + ``` + + Would result in the following HTML: + + ```html + + + <-- the following div will be updated in real time as you type --> + +
    + Lots of text that IS bound +
    + ``` + + Finally, this example really shows the power and ease of Ember when two + properties are bound to eachother via `Ember.computed.alias`. Type into + either text area box and they'll both stay in sync. Note that + `Ember.computed.alias` costs more in terms of performance, so only use it when + your really binding in both directions: + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + writtenWords: "Lots of text that IS bound", + twoWayWrittenWords: Ember.computed.alias("writtenWords") + }); + ``` + + ```handlebars + {{textarea value=writtenWords}} + {{textarea value=twoWayWrittenWords}} + ``` + + ```html + + + <-- both updated in real time --> + + + ``` + + ## Actions + + The helper can send multiple actions based on user events. + + The action property defines the action which is send when + the user presses the return key. + + ```handlebars + {{input action="submit"}} + ``` + + The helper allows some user events to send actions. + + * `enter` + * `insert-newline` + * `escape-press` + * `focus-in` + * `focus-out` + * `key-press` + + For example, if you desire an action to be sent when the input is blurred, + you only need to setup the action name to the event name property. + + ```handlebars + {{textarea focus-in="alertMessage"}} + ``` + + See more about [Text Support Actions](/api/classes/Ember.TextArea.html) + + ## Extension + + Internally, `{{textarea}}` creates an instance of `Ember.TextArea`, passing + arguments from the helper to `Ember.TextArea`'s `create` method. You can + extend the capabilities of text areas in your application by reopening this + class. For example, if you are building a Bootstrap project where `data-*` + attributes are used, you can globally add support for a `data-*` attribute + on all `{{textarea}}`s' in your app by reopening `Ember.TextArea` or + `Ember.TextSupport` and adding it to the `attributeBindings` concatenated + property: + + ```javascript + Ember.TextArea.reopen({ + attributeBindings: ['data-error'] + }); + ``` + + Keep in mind when writing `Ember.TextArea` subclasses that `Ember.TextArea` + itself extends `Ember.Component`, meaning that it does NOT inherit + the `controller` of the parent view. + + See more about [Ember components](/api/classes/Ember.Component.html) + + @method textarea + @for Ember.Handlebars.helpers + @param {Hash} options + */ + function textareaHelper(options) { + + var hash = options.hash; + var types = options.hashTypes; + + return helpers.view.call(this, TextArea, options); + } + + __exports__.textareaHelper = textareaHelper; + }); +enifed("ember-handlebars/controls/checkbox", + ["ember-metal/property_get","ember-metal/property_set","ember-views/views/view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var set = __dependency2__.set; + var View = __dependency3__["default"]; + + /** + @module ember + @submodule ember-handlebars + */ + + /** + The internal class used to create text inputs when the `{{input}}` + helper is used with `type` of `checkbox`. + + See [handlebars.helpers.input](/api/classes/Ember.Handlebars.helpers.html#method_input) for usage details. + + ## Direct manipulation of `checked` + + The `checked` attribute of an `Ember.Checkbox` object should always be set + through the Ember object or by interacting with its rendered element + representation via the mouse, keyboard, or touch. Updating the value of the + checkbox via jQuery will result in the checked value of the object and its + element losing synchronization. + + ## Layout and LayoutName properties + + Because HTML `input` elements are self closing `layout` and `layoutName` + properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s + layout section for more information. + + @class Checkbox + @namespace Ember + @extends Ember.View + */ + __exports__["default"] = View.extend({ + instrumentDisplay: '{{input type="checkbox"}}', + + classNames: ['ember-checkbox'], + + tagName: 'input', + + attributeBindings: [ + 'type', + 'checked', + 'indeterminate', + 'disabled', + 'tabindex', + 'name', + 'autofocus', + 'required', + 'form' + ], + + type: 'checkbox', + checked: false, + disabled: false, + indeterminate: false, + + init: function() { + this._super(); + this.on('change', this, this._updateElementValue); + }, + + didInsertElement: function() { + this._super(); + get(this, 'element').indeterminate = !!get(this, 'indeterminate'); + }, + + _updateElementValue: function() { + set(this, 'checked', this.$().prop('checked')); + } + }); + }); +enifed("ember-handlebars/controls/select", + ["ember-handlebars-compiler","ember-metal/enumerable_utils","ember-metal/property_get","ember-metal/property_set","ember-views/views/view","ember-views/views/collection_view","ember-metal/utils","ember-metal/is_none","ember-metal/computed","ember-runtime/system/native_array","ember-metal/mixin","ember-metal/properties","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var EmberHandlebars = __dependency1__["default"]; + + var forEach = __dependency2__.forEach; + var indexOf = __dependency2__.indexOf; + var indexesOf = __dependency2__.indexesOf; + var replace = __dependency2__.replace; + + var get = __dependency3__.get; + var set = __dependency4__.set; + var View = __dependency5__["default"]; + var CollectionView = __dependency6__["default"]; + var isArray = __dependency7__.isArray; + var isNone = __dependency8__["default"]; + var computed = __dependency9__.computed; + var emberA = __dependency10__.A; + var observer = __dependency11__.observer; + var defineProperty = __dependency12__.defineProperty; + + var precompileTemplate = EmberHandlebars.compile; + + var SelectOption = View.extend({ + instrumentDisplay: 'Ember.SelectOption', + + tagName: 'option', + attributeBindings: ['value', 'selected'], + + defaultTemplate: function(context, options) { + options = { data: options.data, hash: {} }; + EmberHandlebars.helpers.bind.call(context, "view.label", options); + }, + + init: function() { + this.labelPathDidChange(); + this.valuePathDidChange(); + + this._super(); + }, + + selected: computed(function() { + var content = get(this, 'content'); + var selection = get(this, 'parentView.selection'); + if (get(this, 'parentView.multiple')) { + return selection && indexOf(selection, content.valueOf()) > -1; + } else { + // Primitives get passed through bindings as objects... since + // `new Number(4) !== 4`, we use `==` below + return content == selection; // jshint ignore:line + } + }).property('content', 'parentView.selection'), + + labelPathDidChange: observer('parentView.optionLabelPath', function() { + var labelPath = get(this, 'parentView.optionLabelPath'); + + if (!labelPath) { return; } + + defineProperty(this, 'label', computed(function() { + return get(this, labelPath); + }).property(labelPath)); + }), + + valuePathDidChange: observer('parentView.optionValuePath', function() { + var valuePath = get(this, 'parentView.optionValuePath'); + + if (!valuePath) { return; } + + defineProperty(this, 'value', computed(function() { + return get(this, valuePath); + }).property(valuePath)); + }) + }); + + var SelectOptgroup = CollectionView.extend({ + instrumentDisplay: 'Ember.SelectOptgroup', + + tagName: 'optgroup', + attributeBindings: ['label'], + + selectionBinding: 'parentView.selection', + multipleBinding: 'parentView.multiple', + optionLabelPathBinding: 'parentView.optionLabelPath', + optionValuePathBinding: 'parentView.optionValuePath', + + itemViewClassBinding: 'parentView.optionView' + }); + + /** + The `Ember.Select` view class renders a + [select](https://developer.mozilla.org/en/HTML/Element/select) HTML element, + allowing the user to choose from a list of options. + + The text and `value` property of each ` + + + ``` + + The `value` attribute of the selected `"); + return buffer; + } + + function program3(depth0,data) { + + var stack1; + stack1 = helpers.each.call(depth0, "view.groupedContent", {hash:{},hashTypes:{},hashContexts:{},inverse:self.noop,fn:self.program(4, program4, data),contexts:[depth0],types:["ID"],data:data}); + if(stack1 || stack1 === 0) { data.buffer.push(stack1); } + else { data.buffer.push(''); } + } + function program4(depth0,data) { + + + data.buffer.push(escapeExpression(helpers.view.call(depth0, "view.groupView", {hash:{ + 'content': ("content"), + 'label': ("label") + },hashTypes:{'content': "ID",'label': "ID"},hashContexts:{'content': depth0,'label': depth0},contexts:[depth0],types:["ID"],data:data}))); + } + + function program6(depth0,data) { + + var stack1; + stack1 = helpers.each.call(depth0, "view.content", {hash:{},hashTypes:{},hashContexts:{},inverse:self.noop,fn:self.program(7, program7, data),contexts:[depth0],types:["ID"],data:data}); + if(stack1 || stack1 === 0) { data.buffer.push(stack1); } + else { data.buffer.push(''); } + } + function program7(depth0,data) { + + + data.buffer.push(escapeExpression(helpers.view.call(depth0, "view.optionView", {hash:{ + 'content': ("") + },hashTypes:{'content': "ID"},hashContexts:{'content': depth0},contexts:[depth0],types:["ID"],data:data}))); + } + + stack1 = helpers['if'].call(depth0, "view.prompt", {hash:{},hashTypes:{},hashContexts:{},inverse:self.noop,fn:self.program(1, program1, data),contexts:[depth0],types:["ID"],data:data}); + if(stack1 || stack1 === 0) { data.buffer.push(stack1); } + stack1 = helpers['if'].call(depth0, "view.optionGroupPath", {hash:{},hashTypes:{},hashContexts:{},inverse:self.program(6, program6, data),fn:self.program(3, program3, data),contexts:[depth0],types:["ID"],data:data}); + if(stack1 || stack1 === 0) { data.buffer.push(stack1); } + return buffer; + + }), + attributeBindings: ['multiple', 'disabled', 'tabindex', 'name', 'required', 'autofocus', + 'form', 'size'], + + /** + The `multiple` attribute of the select element. Indicates whether multiple + options can be selected. + + @property multiple + @type Boolean + @default false + */ + multiple: false, + + /** + The `disabled` attribute of the select element. Indicates whether + the element is disabled from interactions. + + @property disabled + @type Boolean + @default false + */ + disabled: false, + + /** + The `required` attribute of the select element. Indicates whether + a selected option is required for form validation. + + @property required + @type Boolean + @default false + @since 1.5.0 + */ + required: false, + + /** + The list of options. + + If `optionLabelPath` and `optionValuePath` are not overridden, this should + be a list of strings, which will serve simultaneously as labels and values. + + Otherwise, this should be a list of objects. For instance: + + ```javascript + var App = Ember.Application.create(); + var App.MySelect = Ember.Select.extend({ + content: Ember.A([ + { id: 1, firstName: 'Yehuda' }, + { id: 2, firstName: 'Tom' } + ]), + optionLabelPath: 'content.firstName', + optionValuePath: 'content.id' + }); + ``` + + @property content + @type Array + @default null + */ + content: null, + + /** + When `multiple` is `false`, the element of `content` that is currently + selected, if any. + + When `multiple` is `true`, an array of such elements. + + @property selection + @type Object or Array + @default null + */ + selection: null, + + /** + In single selection mode (when `multiple` is `false`), value can be used to + get the current selection's value or set the selection by it's value. + + It is not currently supported in multiple selection mode. + + @property value + @type String + @default null + */ + value: computed(function(key, value) { + if (arguments.length === 2) { return value; } + var valuePath = get(this, 'optionValuePath').replace(/^content\.?/, ''); + return valuePath ? get(this, 'selection.' + valuePath) : get(this, 'selection'); + }).property('selection'), + + /** + If given, a top-most dummy option will be rendered to serve as a user + prompt. + + @property prompt + @type String + @default null + */ + prompt: null, + + /** + The path of the option labels. See [content](/api/classes/Ember.Select.html#property_content). + + @property optionLabelPath + @type String + @default 'content' + */ + optionLabelPath: 'content', + + /** + The path of the option values. See [content](/api/classes/Ember.Select.html#property_content). + + @property optionValuePath + @type String + @default 'content' + */ + optionValuePath: 'content', + + /** + The path of the option group. + When this property is used, `content` should be sorted by `optionGroupPath`. + + @property optionGroupPath + @type String + @default null + */ + optionGroupPath: null, + + /** + The view class for optgroup. + + @property groupView + @type Ember.View + @default Ember.SelectOptgroup + */ + groupView: SelectOptgroup, + + groupedContent: computed(function() { + var groupPath = get(this, 'optionGroupPath'); + var groupedContent = emberA(); + var content = get(this, 'content') || []; + + forEach(content, function(item) { + var label = get(item, groupPath); + + if (get(groupedContent, 'lastObject.label') !== label) { + groupedContent.pushObject({ + label: label, + content: emberA() + }); + } + + get(groupedContent, 'lastObject.content').push(item); + }); + + return groupedContent; + }).property('optionGroupPath', 'content.@each'), + + /** + The view class for option. + + @property optionView + @type Ember.View + @default Ember.SelectOption + */ + optionView: SelectOption, + + _change: function() { + if (get(this, 'multiple')) { + this._changeMultiple(); + } else { + this._changeSingle(); + } + }, + + selectionDidChange: observer('selection.@each', function() { + var selection = get(this, 'selection'); + if (get(this, 'multiple')) { + if (!isArray(selection)) { + set(this, 'selection', emberA([selection])); + return; + } + this._selectionDidChangeMultiple(); + } else { + this._selectionDidChangeSingle(); + } + }), + + valueDidChange: observer('value', function() { + var content = get(this, 'content'); + var value = get(this, 'value'); + var valuePath = get(this, 'optionValuePath').replace(/^content\.?/, ''); + var selectedValue = (valuePath ? get(this, 'selection.' + valuePath) : get(this, 'selection')); + var selection; + + if (value !== selectedValue) { + selection = content ? content.find(function(obj) { + return value === (valuePath ? get(obj, valuePath) : obj); + }) : null; + + this.set('selection', selection); + } + }), + + + _triggerChange: function() { + var selection = get(this, 'selection'); + var value = get(this, 'value'); + + if (!isNone(selection)) { this.selectionDidChange(); } + if (!isNone(value)) { this.valueDidChange(); } + + this._change(); + }, + + _changeSingle: function() { + var selectedIndex = this.$()[0].selectedIndex; + var content = get(this, 'content'); + var prompt = get(this, 'prompt'); + + if (!content || !get(content, 'length')) { return; } + if (prompt && selectedIndex === 0) { set(this, 'selection', null); return; } + + if (prompt) { selectedIndex -= 1; } + set(this, 'selection', content.objectAt(selectedIndex)); + }, + + + _changeMultiple: function() { + var options = this.$('option:selected'); + var prompt = get(this, 'prompt'); + var offset = prompt ? 1 : 0; + var content = get(this, 'content'); + var selection = get(this, 'selection'); + + if (!content) { return; } + if (options) { + var selectedIndexes = options.map(function() { + return this.index - offset; + }).toArray(); + var newSelection = content.objectsAt(selectedIndexes); + + if (isArray(selection)) { + replace(selection, 0, get(selection, 'length'), newSelection); + } else { + set(this, 'selection', newSelection); + } + } + }, + + _selectionDidChangeSingle: function() { + var el = this.get('element'); + if (!el) { return; } + + var content = get(this, 'content'); + var selection = get(this, 'selection'); + var selectionIndex = content ? indexOf(content, selection) : -1; + var prompt = get(this, 'prompt'); + + if (prompt) { selectionIndex += 1; } + if (el) { el.selectedIndex = selectionIndex; } + }, + + _selectionDidChangeMultiple: function() { + var content = get(this, 'content'); + var selection = get(this, 'selection'); + var selectedIndexes = content ? indexesOf(content, selection) : [-1]; + var prompt = get(this, 'prompt'); + var offset = prompt ? 1 : 0; + var options = this.$('option'); + var adjusted; + + if (options) { + options.each(function() { + adjusted = this.index > -1 ? this.index - offset : -1; + this.selected = indexOf(selectedIndexes, adjusted) > -1; + }); + } + }, + + init: function() { + this._super(); + this.on("didInsertElement", this, this._triggerChange); + this.on("change", this, this._change); + } + }); + + __exports__["default"] = Select; + __exports__.Select = Select; + __exports__.SelectOption = SelectOption; + __exports__.SelectOptgroup = SelectOptgroup; + }); +enifed("ember-handlebars/controls/text_area", + ["ember-metal/property_get","ember-views/views/component","ember-handlebars/controls/text_support","ember-metal/mixin","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + + /** + @module ember + @submodule ember-handlebars + */ + var get = __dependency1__.get; + var Component = __dependency2__["default"]; + var TextSupport = __dependency3__["default"]; + var observer = __dependency4__.observer; + + /** + The internal class used to create textarea element when the `{{textarea}}` + helper is used. + + See [handlebars.helpers.textarea](/api/classes/Ember.Handlebars.helpers.html#method_textarea) for usage details. + + ## Layout and LayoutName properties + + Because HTML `textarea` elements do not contain inner HTML the `layout` and + `layoutName` properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s + layout section for more information. + + @class TextArea + @namespace Ember + @extends Ember.Component + @uses Ember.TextSupport + */ + __exports__["default"] = Component.extend(TextSupport, { + instrumentDisplay: '{{textarea}}', + + classNames: ['ember-text-area'], + + tagName: "textarea", + attributeBindings: ['rows', 'cols', 'name', 'selectionEnd', 'selectionStart', 'wrap', 'lang', 'dir'], + rows: null, + cols: null, + + _updateElementValue: observer('value', function() { + // We do this check so cursor position doesn't get affected in IE + var value = get(this, 'value'); + var $el = this.$(); + if ($el && value !== $el.val()) { + $el.val(value); + } + }), + + init: function() { + this._super(); + this.on("didInsertElement", this, this._updateElementValue); + } + }); + }); +enifed("ember-handlebars/controls/text_field", + ["ember-metal/property_get","ember-metal/property_set","ember-views/views/component","ember-handlebars/controls/text_support","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var get = __dependency1__.get; + var set = __dependency2__.set; + var Component = __dependency3__["default"]; + var TextSupport = __dependency4__["default"]; + + /** + + The internal class used to create text inputs when the `{{input}}` + helper is used with `type` of `text`. + + See [Handlebars.helpers.input](/api/classes/Ember.Handlebars.helpers.html#method_input) for usage details. + + ## Layout and LayoutName properties + + Because HTML `input` elements are self closing `layout` and `layoutName` + properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s + layout section for more information. + + @class TextField + @namespace Ember + @extends Ember.Component + @uses Ember.TextSupport + */ + __exports__["default"] = Component.extend(TextSupport, { + instrumentDisplay: '{{input type="text"}}', + + classNames: ['ember-text-field'], + tagName: "input", + attributeBindings: ['type', 'value', 'size', 'pattern', 'name', 'min', 'max', + 'accept', 'autocomplete', 'autosave', 'formaction', + 'formenctype', 'formmethod', 'formnovalidate', 'formtarget', + 'height', 'inputmode', 'list', 'multiple', 'step', 'lang', 'dir', + 'width'], + + /** + The `value` attribute of the input element. As the user inputs text, this + property is updated live. + + @property value + @type String + @default "" + */ + value: "", + + /** + The `type` attribute of the input element. + + @property type + @type String + @default "text" + */ + type: "text", + + /** + The `size` of the text field in characters. + + @property size + @type String + @default null + */ + size: null, + + /** + The `pattern` attribute of input element. + + @property pattern + @type String + @default null + */ + pattern: null, + + /** + The `min` attribute of input element used with `type="number"` or `type="range"`. + + @property min + @type String + @default null + @since 1.4.0 + */ + min: null, + + /** + The `max` attribute of input element used with `type="number"` or `type="range"`. + + @property max + @type String + @default null + @since 1.4.0 + */ + max: null + }); + }); +enifed("ember-handlebars/controls/text_support", + ["ember-metal/property_get","ember-metal/property_set","ember-metal/mixin","ember-runtime/mixins/target_action_support","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var get = __dependency1__.get; + var set = __dependency2__.set; + var Mixin = __dependency3__.Mixin; + var TargetActionSupport = __dependency4__["default"]; + + /** + Shared mixin used by `Ember.TextField` and `Ember.TextArea`. + + @class TextSupport + @namespace Ember + @uses Ember.TargetActionSupport + @extends Ember.Mixin + @private + */ + var TextSupport = Mixin.create(TargetActionSupport, { + value: "", + + attributeBindings: ['placeholder', 'disabled', 'maxlength', 'tabindex', 'readonly', + 'autofocus', 'form', 'selectionDirection', 'spellcheck', 'required', + 'title', 'autocapitalize', 'autocorrect'], + placeholder: null, + disabled: false, + maxlength: null, + + init: function() { + this._super(); + this.on("focusOut", this, this._elementValueDidChange); + this.on("change", this, this._elementValueDidChange); + this.on("paste", this, this._elementValueDidChange); + this.on("cut", this, this._elementValueDidChange); + this.on("input", this, this._elementValueDidChange); + this.on("keyUp", this, this.interpretKeyEvents); + }, + + /** + The action to be sent when the user presses the return key. + + This is similar to the `{{action}}` helper, but is fired when + the user presses the return key when editing a text field, and sends + the value of the field as the context. + + @property action + @type String + @default null + */ + action: null, + + /** + The event that should send the action. + + Options are: + + * `enter`: the user pressed enter + * `keyPress`: the user pressed a key + + @property onEvent + @type String + @default enter + */ + onEvent: 'enter', + + /** + Whether the `keyUp` event that triggers an `action` to be sent continues + propagating to other views. + + By default, when the user presses the return key on their keyboard and + the text field has an `action` set, the action will be sent to the view's + controller and the key event will stop propagating. + + If you would like parent views to receive the `keyUp` event even after an + action has been dispatched, set `bubbles` to true. + + @property bubbles + @type Boolean + @default false + */ + bubbles: false, + + interpretKeyEvents: function(event) { + var map = TextSupport.KEY_EVENTS; + var method = map[event.keyCode]; + + this._elementValueDidChange(); + if (method) { return this[method](event); } + }, + + _elementValueDidChange: function() { + set(this, 'value', this.$().val()); + }, + + /** + Called when the user inserts a new line. + + Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 13. + Uses sendAction to send the `enter` action. + + @method insertNewline + @param {Event} event + */ + insertNewline: function(event) { + sendAction('enter', this, event); + sendAction('insert-newline', this, event); + }, + + /** + Called when the user hits escape. + + Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 27. + Uses sendAction to send the `escape-press` action. + + @method cancel + @param {Event} event + */ + cancel: function(event) { + sendAction('escape-press', this, event); + }, + + /** + Called when the text area is focused. + + Uses sendAction to send the `focus-in` action. + + @method focusIn + @param {Event} event + */ + focusIn: function(event) { + sendAction('focus-in', this, event); + }, + + /** + Called when the text area is blurred. + + Uses sendAction to send the `focus-out` action. + + @method focusOut + @param {Event} event + */ + focusOut: function(event) { + sendAction('focus-out', this, event); + }, + + /** + Called when the user presses a key. Enabled by setting + the `onEvent` property to `keyPress`. + + Uses sendAction to send the `key-press` action. + + @method keyPress + @param {Event} event + */ + keyPress: function(event) { + sendAction('key-press', this, event); + } + + }); + + TextSupport.KEY_EVENTS = { + 13: 'insertNewline', + 27: 'cancel' + }; + + // In principle, this shouldn't be necessary, but the legacy + // sendAction semantics for TextField are different from + // the component semantics so this method normalizes them. + function sendAction(eventName, view, event) { + var action = get(view, eventName); + var on = get(view, 'onEvent'); + var value = get(view, 'value'); + + // back-compat support for keyPress as an event name even though + // it's also a method name that consumes the event (and therefore + // incompatible with sendAction semantics). + if (on === eventName || (on === 'keyPress' && eventName === 'key-press')) { + view.sendAction('action', value); + } + + view.sendAction(eventName, value); + + if (action || on === eventName) { + if(!get(view, 'bubbles')) { + event.stopPropagation(); + } + } + } + + __exports__["default"] = TextSupport; + }); +enifed("ember-handlebars/ext", + ["ember-metal/core","ember-runtime/system/string","ember-handlebars-compiler","ember-metal/property_get","ember-metal/error","ember-metal/mixin","ember-views/views/view","ember-handlebars/views/metamorph_view","ember-metal/path_cache","ember-metal/is_empty","ember-metal/cache","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.FEATURES, Ember.assert, Ember.Handlebars, Ember.lookup + // var emberAssert = Ember.assert; + + var fmt = __dependency2__.fmt; + + var EmberHandlebars = __dependency3__["default"]; + var helpers = EmberHandlebars.helpers; + + var get = __dependency4__.get; + var EmberError = __dependency5__["default"]; + var IS_BINDING = __dependency6__.IS_BINDING; + + var View = __dependency7__["default"]; + var _Metamorph = __dependency8__._Metamorph; + var detectIsGlobal = __dependency9__.isGlobal; + + // late bound via requireModule because of circular dependencies. + var resolveHelper, SimpleHandlebarsView; + + var isEmpty = __dependency10__["default"]; + + var slice = [].slice; + var originalTemplate = EmberHandlebars.template; + + /** + If a path starts with a reserved keyword, returns the root + that should be used. + + @private + @method normalizePath + @for Ember + @param root {Object} + @param path {String} + @param data {Hash} + */ + + var Cache = __dependency11__["default"]; + + var FIRST_SEGMENT_CACHE = new Cache(1000, function(path){ + return path.split('.', 1)[0]; + }); + + function normalizePath(root, path, data) { + var keywords = (data && data.keywords) || {}; + var keyword, isKeyword; + + // Get the first segment of the path. For example, if the + // path is "foo.bar.baz", returns "foo". + keyword = FIRST_SEGMENT_CACHE.get(path); + + // Test to see if the first path is a keyword that has been + // passed along in the view's data hash. If so, we will treat + // that object as the new root. + if (keywords.hasOwnProperty(keyword)) { + // Look up the value in the template's data hash. + root = keywords[keyword]; + isKeyword = true; + + // Handle cases where the entire path is the reserved + // word. In that case, return the object itself. + if (path === keyword) { + path = ''; + } else { + // Strip the keyword from the path and look up + // the remainder from the newly found root. + path = path.substr(keyword.length+1); + } + } + + return { + root: root, + path: path, + isKeyword: isKeyword + }; + } + + + /** + Lookup both on root and on window. If the path starts with + a keyword, the corresponding object will be looked up in the + template's data hash and used to resolve the path. + + @method get + @for Ember.Handlebars + @param {Object} root The object to look up the property on + @param {String} path The path to be lookedup + @param {Object} options The template's option hash + */ + function handlebarsGet(root, path, options) { + var data = options && options.data; + var normalizedPath = normalizePath(root, path, data); + var value; + + // In cases where the path begins with a keyword, change the + // root to the value represented by that keyword, and ensure + // the path is relative to it. + root = normalizedPath.root; + path = normalizedPath.path; + + // Ember.get with a null root and GlobalPath will fall back to + // Ember.lookup, which is no longer allowed in templates. + // + // But when outputting a primitive, root will be the primitive + // and path a blank string. These primitives should pass through + // to `get`. + if (root || path === '') { + value = get(root, path); + } + + if (detectIsGlobal(path)) { + if (value === undefined && root !== Ember.lookup) { + root = Ember.lookup; + value = get(root, path); + } + if (root === Ember.lookup || root === null) { + } + } + + return value; + } + + function lookupViewInContainer(container, path) { + return container.lookupFactory('view:'+path); + } + + function lookupViewByClassName(path) { + var viewClass; + if (detectIsGlobal(path)) { + viewClass = get(path); + return viewClass; + } + } + + /** + handlebarsGetView resolves a view based on strings passed into a template. + For example: + + ```handlebars + {{view "some-view"}} + {{view view.someView}} + {{view App.SomeView}} {{! deprecated }} + ``` + + A value is first checked to be a string- non-strings are presumed to be + an object and returned. This handles the "access a view on a context" + case (line 2 in the above examples). + + Next a string is normalized, then called on the context with `get`. If + there is still no value, a GlobalPath will be fetched from the global + context (raising a deprecation) and a localPath will be passed to the + container to be looked up. + + @private + @for Ember.Handlebars + @param {Object} context The context of the template being rendered + @param {String} path The path to be lookedup + @param {Object} container The container + @param {Object} options The options from the template + */ + function handlebarsGetView(context, path, container, options) { + var viewClass; + var data; + var pathType; + if (options) { + data = options.data; + pathType = options.types && options.types[0]; + } + + if ('string' === typeof path) { + if('STRING' === pathType && container) { + viewClass = lookupViewInContainer(container, path); + + } + + if(!viewClass) { + viewClass = lookupViewByClassName(path); + } + + if(!viewClass) { + if (data) { + var normalizedPath = normalizePath(context, path, data); + context = normalizedPath.root; + path = normalizedPath.path; + } + + // Only lookup view class on context if there is a context. If not, + // the global lookup path on get may kick in. + viewClass = context && get(context, path); + + if(!viewClass) { + // try the container once more with the normalized path + viewClass = lookupViewInContainer(container, path); + } + } + } else { + viewClass = path; + } + + // Sometimes a view's value is yet another path + if ('string' === typeof viewClass && data && data.view) { + viewClass = handlebarsGetView(data.view, viewClass, container, { + data: data, + types: ['ID'] + }); + } + + + return viewClass; + } + + /** + This method uses `Ember.Handlebars.get` to lookup a value, then ensures + that the value is escaped properly. + + If `unescaped` is a truthy value then the escaping will not be performed. + + @method getEscaped + @for Ember.Handlebars + @param {Object} root The object to look up the property on + @param {String} path The path to be lookedup + @param {Object} options The template's option hash + @since 1.4.0 + */ + function getEscaped(root, path, options) { + var result = handlebarsGet(root, path, options); + + if (result === null || result === undefined) { + result = ""; + } else if (!(result instanceof Handlebars.SafeString)) { + result = String(result); + } + if (!options.hash.unescaped){ + result = Handlebars.Utils.escapeExpression(result); + } + + return result; + } + + __exports__.getEscaped = getEscaped;function resolveParams(context, params, options) { + var resolvedParams = [], types = options.types, param, type; + + for (var i=0, l=params.length; i{{user.name}} + +
    +
    {{user.role.label}}
    + {{user.role.id}} + +

    {{user.role.description}}

    +
    + ``` + + `{{with}}` can be our best friend in these cases, + instead of writing `user.role.*` over and over, we use `{{#with user.role}}`. + Now the context within the `{{#with}} .. {{/with}}` block is `user.role` so you can do the following: + + ```handlebars +
    {{user.name}}
    + +
    + {{#with user.role}} +
    {{label}}
    + {{id}} + +

    {{description}}

    + {{/with}} +
    + ``` + + ### `as` operator + + This operator aliases the scope to a new name. It's helpful for semantic clarity and to retain + default scope or to reference from another `{{with}}` block. + + ```handlebars + // posts might not be + {{#with user.posts as blogPosts}} +
    + There are {{blogPosts.length}} blog posts written by {{user.name}}. +
    + + {{#each post in blogPosts}} +
  • {{post.title}}
  • + {{/each}} + {{/with}} + ``` + + Without the `as` operator, it would be impossible to reference `user.name` in the example above. + + NOTE: The alias should not reuse a name from the bound property path. + For example: `{{#with foo.bar as foo}}` is not supported because it attempts to alias using + the first part of the property path, `foo`. Instead, use `{{#with foo.bar as baz}}`. + + ### `controller` option + + Adding `controller='something'` instructs the `{{with}}` helper to create and use an instance of + the specified controller with the new context as its content. + + This is very similar to using an `itemController` option with the `{{each}}` helper. + + ```handlebars + {{#with users.posts controller='userBlogPosts'}} + {{!- The current context is wrapped in our controller instance }} + {{/with}} + ``` + + In the above example, the template provided to the `{{with}}` block is now wrapped in the + `userBlogPost` controller, which provides a very elegant way to decorate the context with custom + functions/properties. + + @method with + @for Ember.Handlebars.helpers + @param {Function} context + @param {Hash} options + @return {String} HTML string + */ + function withHelper(context, options) { + var bindContext, preserveContext, controller; + var helperName = 'with'; + + if (arguments.length === 4) { + var keywordName, path, rootPath, normalized, contextPath; + + options = arguments[3]; + keywordName = arguments[2]; + path = arguments[0]; + + if (path) { + helperName += ' ' + path + ' as ' + keywordName; + } + + + var localizedOptions = o_create(options); + localizedOptions.data = o_create(options.data); + localizedOptions.data.keywords = o_create(options.data.keywords || {}); + + if (isGlobalPath(path)) { + contextPath = path; + } else { + normalized = normalizePath(this, path, options.data); + path = normalized.path; + rootPath = normalized.root; + + // This is a workaround for the fact that you cannot bind separate objects + // together. When we implement that functionality, we should use it here. + var contextKey = jQuery.expando + guidFor(rootPath); + localizedOptions.data.keywords[contextKey] = rootPath; + // if the path is '' ("this"), just bind directly to the current context + contextPath = path ? contextKey + '.' + path : contextKey; + } + + localizedOptions.hash.keywordName = keywordName; + localizedOptions.hash.keywordPath = contextPath; + + bindContext = this; + context = contextPath; + options = localizedOptions; + preserveContext = true; + } else { + + helperName += ' ' + context; + bindContext = options.contexts[0]; + preserveContext = false; + } + + options.helperName = helperName; + options.isWithHelper = true; + + return bind.call(bindContext, context, options, preserveContext, exists); + } + /** + See [boundIf](/api/classes/Ember.Handlebars.helpers.html#method_boundIf) + and [unboundIf](/api/classes/Ember.Handlebars.helpers.html#method_unboundIf) + + @method if + @for Ember.Handlebars.helpers + @param {Function} context + @param {Hash} options + @return {String} HTML string + */ + function ifHelper(context, options) { + + options.helperName = options.helperName || ('if ' + context); + + if (options.data.isUnbound) { + return helpers.unboundIf.call(options.contexts[0], context, options); + } else { + return helpers.boundIf.call(options.contexts[0], context, options); + } + } + + /** + @method unless + @for Ember.Handlebars.helpers + @param {Function} context + @param {Hash} options + @return {String} HTML string + */ + function unlessHelper(context, options) { + + var fn = options.fn; + var inverse = options.inverse; + var helperName = 'unless'; + + if (context) { + helperName += ' ' + context; + } + + options.fn = inverse; + options.inverse = fn; + + options.helperName = options.helperName || helperName; + + if (options.data.isUnbound) { + return helpers.unboundIf.call(options.contexts[0], context, options); + } else { + return helpers.boundIf.call(options.contexts[0], context, options); + } + } + + /** + `bind-attr` allows you to create a binding between DOM element attributes and + Ember objects. For example: + + ```handlebars + imageTitle + ``` + + The above handlebars template will fill the ``'s `src` attribute with + the value of the property referenced with `"imageUrl"` and its `alt` + attribute with the value of the property referenced with `"imageTitle"`. + + If the rendering context of this template is the following object: + + ```javascript + { + imageUrl: 'http://lolcats.info/haz-a-funny', + imageTitle: 'A humorous image of a cat' + } + ``` + + The resulting HTML output will be: + + ```html + A humorous image of a cat + ``` + + `bind-attr` cannot redeclare existing DOM element attributes. The use of `src` + in the following `bind-attr` example will be ignored and the hard coded value + of `src="/failwhale.gif"` will take precedence: + + ```handlebars + imageTitle + ``` + + ### `bind-attr` and the `class` attribute + + `bind-attr` supports a special syntax for handling a number of cases unique + to the `class` DOM element attribute. The `class` attribute combines + multiple discrete values into a single attribute as a space-delimited + list of strings. Each string can be: + + * a string return value of an object's property. + * a boolean return value of an object's property + * a hard-coded value + + A string return value works identically to other uses of `bind-attr`. The + return value of the property will become the value of the attribute. For + example, the following view and template: + + ```javascript + AView = View.extend({ + someProperty: function() { + return "aValue"; + }.property() + }) + ``` + + ```handlebars + + ``` + + A boolean return value will insert a specified class name if the property + returns `true` and remove the class name if the property returns `false`. + + A class name is provided via the syntax + `somePropertyName:class-name-if-true`. + + ```javascript + AView = View.extend({ + someBool: true + }) + ``` + + ```handlebars + + ``` + + Result in the following rendered output: + + ```html + + ``` + + An additional section of the binding can be provided if you want to + replace the existing class instead of removing it when the boolean + value changes: + + ```handlebars + + ``` + + A hard-coded value can be used by prepending `:` to the desired + class name: `:class-name-to-always-apply`. + + ```handlebars + + ``` + + Results in the following rendered output: + + ```html + + ``` + + All three strategies - string return value, boolean return value, and + hard-coded value – can be combined in a single declaration: + + ```handlebars + + ``` + + @method bind-attr + @for Ember.Handlebars.helpers + @param {Hash} options + @return {String} HTML string + */ + function bindAttrHelper(options) { + var attrs = options.hash; + + + var view = options.data.view; + var ret = []; + + // we relied on the behavior of calling without + // context to mean this === window, but when running + // "use strict", it's possible for this to === undefined; + var ctx = this || window; + + // Generate a unique id for this element. This will be added as a + // data attribute to the element so it can be looked up when + // the bound property changes. + var dataId = uuid(); + + // Handle classes differently, as we can bind multiple classes + var classBindings = attrs['class']; + if (classBindings != null) { + var classResults = bindClasses(ctx, classBindings, view, dataId, options); + + ret.push('class="' + Handlebars.Utils.escapeExpression(classResults.join(' ')) + '"'); + delete attrs['class']; + } + + var attrKeys = keys(attrs); + + // For each attribute passed, create an observer and emit the + // current value of the property as an attribute. + forEach.call(attrKeys, function(attr) { + var path = attrs[attr]; + var normalized; + + + normalized = normalizePath(ctx, path, options.data); + + var value = (path === 'this') ? normalized.root : handlebarsGet(ctx, path, options); + var type = typeOf(value); + + + var observer; + + observer = function observer() { + var result = handlebarsGet(ctx, path, options); + + + var elem = view.$("[data-bindattr-" + dataId + "='" + dataId + "']"); + + // If we aren't able to find the element, it means the element + // to which we were bound has been removed from the view. + // In that case, we can assume the template has been re-rendered + // and we need to clean up the observer. + if (!elem || elem.length === 0) { + removeObserver(normalized.root, normalized.path, observer); + return; + } + + View.applyAttributeBindings(elem, attr, result); + }; + + // Add an observer to the view for when the property changes. + // When the observer fires, find the element using the + // unique data id and update the attribute to the new value. + // Note: don't add observer when path is 'this' or path + // is whole keyword e.g. {{#each x in list}} ... {{bind-attr attr="x"}} + if (path !== 'this' && !(normalized.isKeyword && normalized.path === '' )) { + view.registerObserver(normalized.root, normalized.path, observer); + } + + // if this changes, also change the logic in ember-views/lib/views/view.js + if ((type === 'string' || (type === 'number' && !isNaN(value)))) { + ret.push(attr + '="' + Handlebars.Utils.escapeExpression(value) + '"'); + } else if (value && type === 'boolean') { + // The developer controls the attr name, so it should always be safe + ret.push(attr + '="' + attr + '"'); + } + }, this); + + // Add the unique identifier + // NOTE: We use all lower-case since Firefox has problems with mixed case in SVG + ret.push('data-bindattr-' + dataId + '="' + dataId + '"'); + return new SafeString(ret.join(' ')); + } + + /** + See `bind-attr` + + @method bindAttr + @for Ember.Handlebars.helpers + @deprecated + @param {Function} context + @param {Hash} options + @return {String} HTML string + */ + function bindAttrHelperDeprecated() { + return helpers['bind-attr'].apply(this, arguments); + } + + /** + Helper that, given a space-separated string of property paths and a context, + returns an array of class names. Calling this method also has the side + effect of setting up observers at those property paths, such that if they + change, the correct class name will be reapplied to the DOM element. + + For example, if you pass the string "fooBar", it will first look up the + "fooBar" value of the context. If that value is true, it will add the + "foo-bar" class to the current element (i.e., the dasherized form of + "fooBar"). If the value is a string, it will add that string as the class. + Otherwise, it will not add any new class name. + + @private + @method bindClasses + @for Ember.Handlebars + @param {Ember.Object} context The context from which to lookup properties + @param {String} classBindings A string, space-separated, of class bindings + to use + @param {View} view The view in which observers should look for the + element to update + @param {Srting} bindAttrId Optional bindAttr id used to lookup elements + @return {Array} An array of class names to add + */ + function bindClasses(context, classBindings, view, bindAttrId, options) { + var ret = []; + var newClass, value, elem; + + // Helper method to retrieve the property from the context and + // determine which class string to return, based on whether it is + // a Boolean or not. + var classStringForPath = function(root, parsedPath, options) { + var val; + var path = parsedPath.path; + + if (path === 'this') { + val = root; + } else if (path === '') { + val = true; + } else { + val = handlebarsGet(root, path, options); + } + + return View._classStringForValue(path, val, parsedPath.className, parsedPath.falsyClassName); + }; + + // For each property passed, loop through and setup + // an observer. + forEach.call(classBindings.split(' '), function(binding) { + + // Variable in which the old class value is saved. The observer function + // closes over this variable, so it knows which string to remove when + // the property changes. + var oldClass; + var observer; + var parsedPath = View._parsePropertyPath(binding); + var path = parsedPath.path; + var pathRoot = context; + var normalized; + + if (path !== '' && path !== 'this') { + normalized = normalizePath(context, path, options.data); + + pathRoot = normalized.root; + path = normalized.path; + } + + // Set up an observer on the context. If the property changes, toggle the + // class name. + observer = function() { + // Get the current value of the property + newClass = classStringForPath(context, parsedPath, options); + elem = bindAttrId ? view.$("[data-bindattr-" + bindAttrId + "='" + bindAttrId + "']") : view.$(); + + // If we can't find the element anymore, a parent template has been + // re-rendered and we've been nuked. Remove the observer. + if (!elem || elem.length === 0) { + removeObserver(pathRoot, path, observer); + } else { + // If we had previously added a class to the element, remove it. + if (oldClass) { + elem.removeClass(oldClass); + } + + // If necessary, add a new class. Make sure we keep track of it so + // it can be removed in the future. + if (newClass) { + elem.addClass(newClass); + oldClass = newClass; + } else { + oldClass = null; + } + } + }; + + if (path !== '' && path !== 'this') { + view.registerObserver(pathRoot, path, observer); + } + + // We've already setup the observer; now we just need to figure out the + // correct behavior right now on the first pass through. + value = classStringForPath(context, parsedPath, options); + + if (value) { + ret.push(value); + + // Make sure we save the current value so that it can be removed if the + // observer fires. + oldClass = value; + } + }); + + return ret; + } + + __exports__.bind = bind; + __exports__._triageMustacheHelper = _triageMustacheHelper; + __exports__.resolveHelper = resolveHelper; + __exports__.bindHelper = bindHelper; + __exports__.boundIfHelper = boundIfHelper; + __exports__.unboundIfHelper = unboundIfHelper; + __exports__.withHelper = withHelper; + __exports__.ifHelper = ifHelper; + __exports__.unlessHelper = unlessHelper; + __exports__.bindAttrHelper = bindAttrHelper; + __exports__.bindAttrHelperDeprecated = bindAttrHelperDeprecated; + __exports__.bindClasses = bindClasses; + }); +enifed("ember-handlebars/helpers/collection", + ["ember-metal/core","ember-metal/utils","ember-handlebars-compiler","ember-runtime/system/string","ember-metal/property_get","ember-handlebars/ext","ember-handlebars/helpers/view","ember-metal/computed","ember-views/views/collection_view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var Ember = __dependency1__["default"]; + // Ember.assert, Ember.deprecate + var inspect = __dependency2__.inspect; + + // var emberAssert = Ember.assert; + // emberDeprecate = Ember.deprecate; + + var EmberHandlebars = __dependency3__["default"]; + var helpers = EmberHandlebars.helpers; + + var fmt = __dependency4__.fmt; + var get = __dependency5__.get; + var handlebarsGet = __dependency6__.handlebarsGet; + var handlebarsGetView = __dependency6__.handlebarsGetView; + var ViewHelper = __dependency7__.ViewHelper; + var computed = __dependency8__.computed; + var CollectionView = __dependency9__["default"]; + + var alias = computed.alias; + /** + `{{collection}}` is a `Ember.Handlebars` helper for adding instances of + `Ember.CollectionView` to a template. See [Ember.CollectionView](/api/classes/Ember.CollectionView.html) + for additional information on how a `CollectionView` functions. + + `{{collection}}`'s primary use is as a block helper with a `contentBinding` + option pointing towards an `Ember.Array`-compatible object. An `Ember.View` + instance will be created for each item in its `content` property. Each view + will have its own `content` property set to the appropriate item in the + collection. + + The provided block will be applied as the template for each item's view. + + Given an empty `` the following template: + + ```handlebars + {{! application.hbs }} + {{#collection content=model}} + Hi {{view.content.name}} + {{/collection}} + ``` + + And the following application code + + ```javascript + App = Ember.Application.create(); + App.ApplicationRoute = Ember.Route.extend({ + model: function(){ + return [{name: 'Yehuda'},{name: 'Tom'},{name: 'Peter'}]; + } + }); + ``` + + The following HTML will result: + + ```html +
    +
    Hi Yehuda
    +
    Hi Tom
    +
    Hi Peter
    +
    + ``` + + ### Non-block version of collection + + If you provide an `itemViewClass` option that has its own `template` you may + omit the block. + + The following template: + + ```handlebars + {{! application.hbs }} + {{collection content=model itemViewClass="an-item"}} + ``` + + And application code + + ```javascript + App = Ember.Application.create(); + App.ApplicationRoute = Ember.Route.extend({ + model: function(){ + return [{name: 'Yehuda'},{name: 'Tom'},{name: 'Peter'}]; + } + }); + + App.AnItemView = Ember.View.extend({ + template: Ember.Handlebars.compile("Greetings {{view.content.name}}") + }); + ``` + + Will result in the HTML structure below + + ```html +
    +
    Greetings Yehuda
    +
    Greetings Tom
    +
    Greetings Peter
    +
    + ``` + + ### Specifying a CollectionView subclass + + By default the `{{collection}}` helper will create an instance of + `Ember.CollectionView`. You can supply a `Ember.CollectionView` subclass to + the helper by passing it as the first argument: + + ```handlebars + {{#collection "my-custom-collection" content=model}} + Hi {{view.content.name}} + {{/collection}} + ``` + + This example would look for the class `App.MyCustomCollection`. + + ### Forwarded `item.*`-named Options + + As with the `{{view}}`, helper options passed to the `{{collection}}` will be + set on the resulting `Ember.CollectionView` as properties. Additionally, + options prefixed with `item` will be applied to the views rendered for each + item (note the camelcasing): + + ```handlebars + {{#collection content=model + itemTagName="p" + itemClassNames="greeting"}} + Howdy {{view.content.name}} + {{/collection}} + ``` + + Will result in the following HTML structure: + + ```html +
    +

    Howdy Yehuda

    +

    Howdy Tom

    +

    Howdy Peter

    +
    + ``` + + @method collection + @for Ember.Handlebars.helpers + @param {String} path + @param {Hash} options + @return {String} HTML string + @deprecated Use `{{each}}` helper instead. + */ + function collectionHelper(path, options) { + + // If no path is provided, treat path param as options. + if (path && path.data && path.data.isRenderData) { + options = path; + path = undefined; + } else { + } + + var fn = options.fn, + data = options.data, + inverse = options.inverse, + view = options.data.view, + // This should be deterministic, and should probably come from a + // parent view and not the controller. + container = (view.controller && view.controller.container ? view.controller.container : view.container); + + // If passed a path string, convert that into an object. + // Otherwise, just default to the standard class. + var collectionClass; + if (path) { + collectionClass = handlebarsGetView(this, path, container, options); + } + else { + collectionClass = CollectionView; + } + + var hash = options.hash; + var itemHash = {}; + var match; + + // Extract item view class if provided else default to the standard class + var collectionPrototype = collectionClass.proto(); + var itemViewClass; + + if (hash.itemView) { + itemViewClass = handlebarsGetView(this, hash.itemView, container, options); + } else if (hash.itemViewClass) { + itemViewClass = handlebarsGetView(collectionPrototype, hash.itemViewClass, container, options); + } else { + itemViewClass = handlebarsGetView(collectionPrototype, collectionPrototype.itemViewClass, container, options); + } + + + delete hash.itemViewClass; + delete hash.itemView; + + // Go through options passed to the {{collection}} helper and extract options + // that configure item views instead of the collection itself. + for (var prop in hash) { + if (hash.hasOwnProperty(prop)) { + match = prop.match(/^item(.)(.*)$/); + + if (match && prop !== 'itemController') { + // Convert itemShouldFoo -> shouldFoo + itemHash[match[1].toLowerCase() + match[2]] = hash[prop]; + // Delete from hash as this will end up getting passed to the + // {{view}} helper method. + delete hash[prop]; + } + } + } + + if (fn) { + itemHash.template = fn; + delete options.fn; + } + + var emptyViewClass; + if (inverse && inverse !== EmberHandlebars.VM.noop) { + emptyViewClass = get(collectionPrototype, 'emptyViewClass'); + emptyViewClass = emptyViewClass.extend({ + template: inverse, + tagName: itemHash.tagName + }); + } else if (hash.emptyViewClass) { + emptyViewClass = handlebarsGetView(this, hash.emptyViewClass, container, options); + } + if (emptyViewClass) { hash.emptyView = emptyViewClass; } + + if (hash.keyword) { + itemHash._context = this; + } else { + itemHash._context = alias('content'); + } + + var viewOptions = ViewHelper.propertiesFromHTMLOptions({ data: data, hash: itemHash }, this); + hash.itemViewClass = itemViewClass.extend(viewOptions); + + options.helperName = options.helperName || 'collection'; + + return helpers.view.call(this, collectionClass, options); + } + + __exports__["default"] = collectionHelper; + }); +enifed("ember-handlebars/helpers/debug", + ["ember-metal/core","ember-metal/utils","ember-metal/logger","ember-metal/property_get","ember-handlebars/ext","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + /*jshint debug:true*/ + + /** + @module ember + @submodule ember-handlebars + */ + var Ember = __dependency1__["default"]; + // Ember.FEATURES, + var inspect = __dependency2__.inspect; + var Logger = __dependency3__["default"]; + + var get = __dependency4__.get; + var normalizePath = __dependency5__.normalizePath; + var handlebarsGet = __dependency5__.handlebarsGet; + + var a_slice = [].slice; + + /** + `log` allows you to output the value of variables in the current rendering + context. `log` also accepts primitive types such as strings or numbers. + + ```handlebars + {{log "myVariable:" myVariable }} + ``` + + @method log + @for Ember.Handlebars.helpers + @param {String} property + */ + function logHelper() { + var params = a_slice.call(arguments, 0, -1); + var options = arguments[arguments.length - 1]; + var logger = Logger.log; + var values = []; + var allowPrimitives = true; + + for (var i = 0; i < params.length; i++) { + var type = options.types[i]; + + if (type === 'ID' || !allowPrimitives) { + var context = (options.contexts && options.contexts[i]) || this; + var normalized = normalizePath(context, params[i], options.data); + + if (normalized.path === 'this') { + values.push(normalized.root); + } else { + values.push(handlebarsGet(normalized.root, normalized.path, options)); + } + } else { + values.push(params[i]); + } + } + + logger.apply(logger, values); + } + + /** + Execute the `debugger` statement in the current context. + + ```handlebars + {{debugger}} + ``` + + Before invoking the `debugger` statement, there + are a few helpful variables defined in the + body of this helper that you can inspect while + debugging that describe how and where this + helper was invoked: + + - templateContext: this is most likely a controller + from which this template looks up / displays properties + - typeOfTemplateContext: a string description of + what the templateContext is + + For example, if you're wondering why a value `{{foo}}` + isn't rendering as expected within a template, you + could place a `{{debugger}}` statement, and when + the `debugger;` breakpoint is hit, you can inspect + `templateContext`, determine if it's the object you + expect, and/or evaluate expressions in the console + to perform property lookups on the `templateContext`: + + ``` + > templateContext.get('foo') // -> "" + ``` + + @method debugger + @for Ember.Handlebars.helpers + @param {String} property + */ + function debuggerHelper(options) { + + // These are helpful values you can inspect while debugging. + var templateContext = this; + var typeOfTemplateContext = inspect(templateContext); + + debugger; + } + + __exports__.logHelper = logHelper; + __exports__.debuggerHelper = debuggerHelper; + }); +enifed("ember-handlebars/helpers/each", + ["ember-metal/core","ember-handlebars-compiler","ember-runtime/system/string","ember-metal/property_get","ember-metal/property_set","ember-views/views/collection_view","ember-metal/binding","ember-runtime/mixins/controller","ember-runtime/controllers/array_controller","ember-runtime/mixins/array","ember-runtime/copy","ember-metal/run_loop","ember-metal/events","ember-handlebars/ext","ember-metal/computed","ember-metal/observer","ember-handlebars/views/metamorph_view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __exports__) { + "use strict"; + + /** + @module ember + @submodule ember-handlebars + */ + var Ember = __dependency1__["default"]; + // Ember.assert;, Ember.K + var K = Ember.K; + + var EmberHandlebars = __dependency2__["default"]; + var helpers = EmberHandlebars.helpers; + + var fmt = __dependency3__.fmt; + var get = __dependency4__.get; + var set = __dependency5__.set; + var CollectionView = __dependency6__["default"]; + var Binding = __dependency7__.Binding; + var ControllerMixin = __dependency8__["default"]; + var ArrayController = __dependency9__["default"]; + var EmberArray = __dependency10__["default"]; + var copy = __dependency11__["default"]; + var run = __dependency12__["default"]; + var on = __dependency13__.on; + var handlebarsGet = __dependency14__.handlebarsGet; + var computed = __dependency15__.computed; + + var addObserver = __dependency16__.addObserver; + var removeObserver = __dependency16__.removeObserver; + var addBeforeObserver = __dependency16__.addBeforeObserver; + var removeBeforeObserver = __dependency16__.removeBeforeObserver; + + var _Metamorph = __dependency17__._Metamorph; + var _MetamorphView = __dependency17__._MetamorphView; + + var EachView = CollectionView.extend(_Metamorph, { + + init: function() { + var itemController = get(this, 'itemController'); + var binding; + + if (itemController) { + var controller = get(this, 'controller.container').lookupFactory('controller:array').create({ + _isVirtual: true, + parentController: get(this, 'controller'), + itemController: itemController, + target: get(this, 'controller'), + _eachView: this + }); + + this.disableContentObservers(function() { + set(this, 'content', controller); + binding = new Binding('content', '_eachView.dataSource').oneWay(); + binding.connect(controller); + }); + + set(this, '_arrayController', controller); + } else { + this.disableContentObservers(function() { + binding = new Binding('content', 'dataSource').oneWay(); + binding.connect(this); + }); + } + + return this._super(); + }, + + _assertArrayLike: function(content) { + }, + + disableContentObservers: function(callback) { + removeBeforeObserver(this, 'content', null, '_contentWillChange'); + removeObserver(this, 'content', null, '_contentDidChange'); + + callback.call(this); + + addBeforeObserver(this, 'content', null, '_contentWillChange'); + addObserver(this, 'content', null, '_contentDidChange'); + }, + + itemViewClass: _MetamorphView, + emptyViewClass: _MetamorphView, + + createChildView: function(view, attrs) { + view = this._super(view, attrs); + + // At the moment, if a container view subclass wants + // to insert keywords, it is responsible for cloning + // the keywords hash. This will be fixed momentarily. + var keyword = get(this, 'keyword'); + var content = get(view, 'content'); + + if (keyword) { + var data = get(view, 'templateData'); + + data = copy(data); + data.keywords = view.cloneKeywords(); + set(view, 'templateData', data); + + // In this case, we do not bind, because the `content` of + // a #each item cannot change. + data.keywords[keyword] = content; + } + + // If {{#each}} is looping over an array of controllers, + // point each child view at their respective controller. + if (content && content.isController) { + set(view, 'controller', content); + } + + return view; + }, + + destroy: function() { + if (!this._super()) { return; } + + var arrayController = get(this, '_arrayController'); + + if (arrayController) { + arrayController.destroy(); + } + + return this; + } + }); + + var GroupedEach = EmberHandlebars.GroupedEach = function(context, path, options) { + var self = this; + var normalized = EmberHandlebars.normalizePath(context, path, options.data); + + this.context = context; + this.path = path; + this.options = options; + this.template = options.fn; + this.containingView = options.data.view; + this.normalizedRoot = normalized.root; + this.normalizedPath = normalized.path; + this.content = this.lookupContent(); + + this.addContentObservers(); + this.addArrayObservers(); + + this.containingView.on('willClearRender', function() { + self.destroy(); + }); + }; + + GroupedEach.prototype = { + contentWillChange: function() { + this.removeArrayObservers(); + }, + + contentDidChange: function() { + this.content = this.lookupContent(); + this.addArrayObservers(); + this.rerenderContainingView(); + }, + + contentArrayWillChange: K, + + contentArrayDidChange: function() { + this.rerenderContainingView(); + }, + + lookupContent: function() { + return handlebarsGet(this.normalizedRoot, this.normalizedPath, this.options); + }, + + addArrayObservers: function() { + if (!this.content) { return; } + + this.content.addArrayObserver(this, { + willChange: 'contentArrayWillChange', + didChange: 'contentArrayDidChange' + }); + }, + + removeArrayObservers: function() { + if (!this.content) { return; } + + this.content.removeArrayObserver(this, { + willChange: 'contentArrayWillChange', + didChange: 'contentArrayDidChange' + }); + }, + + addContentObservers: function() { + addBeforeObserver(this.normalizedRoot, this.normalizedPath, this, this.contentWillChange); + addObserver(this.normalizedRoot, this.normalizedPath, this, this.contentDidChange); + }, + + removeContentObservers: function() { + removeBeforeObserver(this.normalizedRoot, this.normalizedPath, this.contentWillChange); + removeObserver(this.normalizedRoot, this.normalizedPath, this.contentDidChange); + }, + + render: function() { + if (!this.content) { return; } + + var content = this.content; + var contentLength = get(content, 'length'); + var options = this.options; + var data = options.data; + var template = this.template; + + data.insideEach = true; + for (var i = 0; i < contentLength; i++) { + var context = content.objectAt(i); + options.data.keywords[options.hash.keyword] = context; + template(context, { data: data }); + } + }, + + rerenderContainingView: function() { + var self = this; + run.scheduleOnce('render', this, function() { + // It's possible it's been destroyed after we enqueued a re-render call. + if (!self.destroyed) { + self.containingView.rerender(); + } + }); + }, + + destroy: function() { + this.removeContentObservers(); + if (this.content) { + this.removeArrayObservers(); + } + this.destroyed = true; + } + }; + + /** + The `{{#each}}` helper loops over elements in a collection. It is an extension + of the base Handlebars `{{#each}}` helper. + + The default behavior of `{{#each}}` is to yield its inner block once for every + item in an array. Each yield will provide the item as the context of the block. + + ```javascript + var developers = [{name: 'Yehuda'},{name: 'Tom'}, {name: 'Paul'}]; + ``` + + ```handlebars + {{#each developers}} + {{name}} + {{! `this` is each developer }} + {{/each}} + ``` + + `{{#each}}` supports an alternative syntax with element naming. This preserves + context of the yielded block: + + ```handlebars + {{#each person in developers}} + {{person.name}} + {{! `this` is whatever it was outside the #each }} + {{/each}} + ``` + + The same rules apply to arrays of primitives, but the items may need to be + references with `{{this}}`. + + ```javascript + var developerNames = ['Yehuda', 'Tom', 'Paul'] + ``` + + ```handlebars + {{#each developerNames}} + {{this}} + {{/each}} + ``` + + ### {{else}} condition + + `{{#each}}` can have a matching `{{else}}`. The contents of this block will render + if the collection is empty. + + ``` + {{#each person in developers}} + {{person.name}} + {{else}} +

    Sorry, nobody is available for this task.

    + {{/each}} + ``` + + ### Specifying an alternative view for each item + + `itemViewClass` can control which view will be used during the render of each + item's template. + + The following template: + + ```handlebars +
      + {{#each developers itemViewClass="person"}} + {{name}} + {{/each}} +
    + ``` + + Will use the following view for each item + + ```javascript + App.PersonView = Ember.View.extend({ + tagName: 'li' + }); + ``` + + Resulting in HTML output that looks like the following: + + ```html +
      +
    • Yehuda
    • +
    • Tom
    • +
    • Paul
    • +
    + ``` + + `itemViewClass` also enables a non-block form of `{{each}}`. The view + must {{#crossLink "Ember.View/toc_templates"}}provide its own template{{/crossLink}}, + and then the block should be dropped. An example that outputs the same HTML + as the previous one: + + ```javascript + App.PersonView = Ember.View.extend({ + tagName: 'li', + template: '{{name}}' + }); + ``` + + ```handlebars +
      + {{each developers itemViewClass="person"}} +
    + ``` + + ### Specifying an alternative view for no items (else) + + The `emptyViewClass` option provides the same flexibility to the `{{else}}` + case of the each helper. + + ```javascript + App.NoPeopleView = Ember.View.extend({ + tagName: 'li', + template: 'No person is available, sorry' + }); + ``` + + ```handlebars +
      + {{#each developers emptyViewClass="no-people"}} +
    • {{name}}
    • + {{/each}} +
    + ``` + + ### Wrapping each item in a controller + + Controllers in Ember manage state and decorate data. In many cases, + providing a controller for each item in a list can be useful. + Specifically, an {{#crossLink "Ember.ObjectController"}}Ember.ObjectController{{/crossLink}} + should probably be used. Item controllers are passed the item they + will present as a `model` property, and an object controller will + proxy property lookups to `model` for us. + + This allows state and decoration to be added to the controller + while any other property lookups are delegated to the model. An example: + + ```javascript + App.RecruitController = Ember.ObjectController.extend({ + isAvailableForHire: function() { + return !this.get('isEmployed') && this.get('isSeekingWork'); + }.property('isEmployed', 'isSeekingWork') + }) + ``` + + ```handlebars + {{#each person in developers itemController="recruit"}} + {{person.name}} {{#if person.isAvailableForHire}}Hire me!{{/if}} + {{/each}} + ``` + + ### (Experimental) Grouped Each + + If a list's membership often changes, but properties of items in that + group rarely change, a significant improvement in template rendering + time can be achieved by using the experimental [group helper](https://github.com/emberjs/group-helper). + + ```handlebars + {{#group}} + {{#each people}} + {{firstName}} {{lastName}} + {{/each}} + {{/group}} + ``` + + When the membership of `people` changes, or when any property changes, the entire + `{{#group}}` block will be re-rendered. + + An `{{#each}}` inside the `{{#group}}` helper can opt-out of the special group + behavior by passing the `groupedRows` option. For example: + + ```handlebars + {{#group}} + {{#each dealers}} + {{! uses group's special behavior }} + {{firstName}} {{lastName}} + {{/each}} + + {{#each car in cars groupedRows=true}} + {{! does not use group's special behavior }} + {{car.make}} {{car.model}} {{car.color}} + {{/each}} + {{/group}} + ``` + + Any change to the `dealers` collection will cause the entire group to be re-rendered. + Changes to the `cars` collection will be re-rendered individually, as they are with + normal `{{#each}}` usage. + + `{{#group}}` is implemented with an `itemViewClass`, so specifying an `itemViewClass` + on an `{{#each}}` will also disable the special re-rendering behavior. + + @method each + @for Ember.Handlebars.helpers + @param [name] {String} name for item (used with `in`) + @param [path] {String} path + @param [options] {Object} Handlebars key/value pairs of options + @param [options.itemViewClass] {String} a path to a view class used for each item + @param [options.emptyViewClass] {String} a path to a view class used for each item + @param [options.itemController] {String} name of a controller to be created for each item + @param [options.groupedRows] {boolean} enable normal item-by-item rendering when inside a `#group` helper + */ + function eachHelper(path, options) { + var ctx; + var helperName = 'each'; + + if (arguments.length === 4) { + + var keywordName = arguments[0]; + + + options = arguments[3]; + path = arguments[2]; + + helperName += ' ' + keywordName + ' in ' + path; + + if (path === '') { path = "this"; } + + options.hash.keyword = keywordName; + + } else if (arguments.length === 1) { + options = path; + path = 'this'; + } else { + helperName += ' ' + path; + } + + options.hash.dataSourceBinding = path; + // Set up emptyView as a metamorph with no tag + //options.hash.emptyViewClass = Ember._MetamorphView; + + // can't rely on this default behavior when use strict + ctx = this || window; + + options.helperName = options.helperName || helperName; + + if (options.data.insideGroup && !options.hash.groupedRows && !options.hash.itemViewClass) { + new GroupedEach(ctx, path, options).render(); + } else { + return helpers.collection.call(ctx, EmberHandlebars.EachView, options); + } + } + + __exports__.EachView = EachView; + __exports__.GroupedEach = GroupedEach; + __exports__.eachHelper = eachHelper; + }); +enifed("ember-handlebars/helpers/loc", + ["ember-runtime/system/string","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var loc = __dependency1__.loc; + + /** + @module ember + @submodule ember-handlebars + */ + + /** + Calls [Ember.String.loc](/api/classes/Ember.String.html#method_loc) with the + provided string. + + This is a convenient way to localize text within a template: + + ```javascript + Ember.STRINGS = { + '_welcome_': 'Bonjour' + }; + ``` + + ```handlebars +
    + {{loc '_welcome_'}} +
    + ``` + + ```html +
    + Bonjour +
    + ``` + + See [Ember.String.loc](/api/classes/Ember.String.html#method_loc) for how to + set up localized string references. + + @method loc + @for Ember.Handlebars.helpers + @param {String} str The string to format + @see {Ember.String#loc} + */ + __exports__["default"] = loc; + }); +enifed("ember-handlebars/helpers/partial", + ["ember-metal/core","ember-metal/is_none","ember-handlebars/ext","ember-handlebars/helpers/binding","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert + // var emberAssert = Ember.assert; + + var isNone = __dependency2__.isNone; + var handlebarsGet = __dependency3__.handlebarsGet; + var bind = __dependency4__.bind; + + /** + @module ember + @submodule ember-handlebars + */ + + /** + The `partial` helper renders another template without + changing the template context: + + ```handlebars + {{foo}} + {{partial "nav"}} + ``` + + The above example template will render a template named + "_nav", which has the same context as the parent template + it's rendered into, so if the "_nav" template also referenced + `{{foo}}`, it would print the same thing as the `{{foo}}` + in the above example. + + If a "_nav" template isn't found, the `partial` helper will + fall back to a template named "nav". + + ## Bound template names + + The parameter supplied to `partial` can also be a path + to a property containing a template name, e.g.: + + ```handlebars + {{partial someTemplateName}} + ``` + + The above example will look up the value of `someTemplateName` + on the template context (e.g. a controller) and use that + value as the name of the template to render. If the resolved + value is falsy, nothing will be rendered. If `someTemplateName` + changes, the partial will be re-rendered using the new template + name. + + ## Setting the partial's context with `with` + + The `partial` helper can be used in conjunction with the `with` + helper to set a context that will be used by the partial: + + ```handlebars + {{#with currentUser}} + {{partial "user_info"}} + {{/with}} + ``` + + @method partial + @for Ember.Handlebars.helpers + @param {String} partialName the name of the template to render minus the leading underscore + */ + + __exports__["default"] = function partialHelper(name, options) { + + var context = (options.contexts && options.contexts.length) ? options.contexts[0] : this; + + options.helperName = options.helperName || 'partial'; + + if (options.types[0] === "ID") { + // Helper was passed a property path; we need to + // create a binding that will re-render whenever + // this property changes. + options.fn = function(context, fnOptions) { + var partialName = handlebarsGet(context, name, fnOptions); + renderPartial(context, partialName, fnOptions); + }; + + return bind.call(context, name, options, true, exists); + } else { + // Render the partial right into parent template. + renderPartial(context, name, options); + } + } + + function exists(value) { + return !isNone(value); + } + + function renderPartial(context, name, options) { + var nameParts = name.split("/"); + var lastPart = nameParts[nameParts.length - 1]; + + nameParts[nameParts.length - 1] = "_" + lastPart; + + var view = options.data.view; + var underscoredName = nameParts.join("/"); + var template = view.templateForName(underscoredName); + var deprecatedTemplate = !template && view.templateForName(name); + + + template = template || deprecatedTemplate; + + template(context, { data: options.data }); + } + }); +enifed("ember-handlebars/helpers/shared", + ["ember-handlebars/ext","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var handlebarsGet = __dependency1__.handlebarsGet; + + __exports__["default"] = function resolvePaths(options) { + var ret = []; + var contexts = options.contexts; + var roots = options.roots; + var data = options.data; + + for (var i=0, l=contexts.length; i{{unbound somePropertyThatDoesntChange}}
    + ``` + + `unbound` can also be used in conjunction with a bound helper to + render it in its unbound form: + + ```handlebars +
    {{unbound helperName somePropertyThatDoesntChange}}
    + ``` + + @method unbound + @for Ember.Handlebars.helpers + @param {String} property + @return {String} HTML string + */ + __exports__["default"] = function unboundHelper(property, fn) { + var options = arguments[arguments.length - 1]; + var container = options.data.view.container; + var helper, context, out, ctx; + + ctx = this; + if (arguments.length > 2) { + // Unbound helper call. + options.data.isUnbound = true; + helper = resolveHelper(container, property) || helpers.helperMissing; + out = helper.apply(ctx, slice.call(arguments, 1)); + delete options.data.isUnbound; + return out; + } + + context = (fn.contexts && fn.contexts.length) ? fn.contexts[0] : ctx; + return handlebarsGet(context, property, fn); + } + }); +enifed("ember-handlebars/helpers/view", + ["ember-metal/core","ember-runtime/system/object","ember-metal/property_get","ember-metal/property_set","ember-metal/mixin","ember-views/system/jquery","ember-views/views/view","ember-metal/binding","ember-metal/keys","ember-handlebars/ext","ember-runtime/system/string","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { + "use strict"; + /*globals Handlebars */ + + /** + @module ember + @submodule ember-handlebars + */ + + var Ember = __dependency1__["default"]; + // Ember.warn, Ember.assert + // var emberWarn = Ember.warn, emberAssert = Ember.assert; + + var EmberObject = __dependency2__["default"]; + var get = __dependency3__.get; + var set = __dependency4__.set; + var IS_BINDING = __dependency5__.IS_BINDING; + var jQuery = __dependency6__["default"]; + var View = __dependency7__["default"]; + var isGlobalPath = __dependency8__.isGlobalPath; + var keys = __dependency9__["default"]; + var normalizePath = __dependency10__.normalizePath; + var handlebarsGet = __dependency10__.handlebarsGet; + var handlebarsGetView = __dependency10__.handlebarsGetView; + var EmberString = __dependency11__["default"]; + + + var LOWERCASE_A_Z = /^[a-z]/; + var VIEW_PREFIX = /^view\./; + + function makeBindings(thisContext, options) { + var hash = options.hash; + var hashType = options.hashTypes; + + for (var prop in hash) { + if (hashType[prop] === 'ID') { + + var value = hash[prop]; + + if (IS_BINDING.test(prop)) { + } else { + hash[prop + 'Binding'] = value; + hashType[prop + 'Binding'] = 'STRING'; + delete hash[prop]; + delete hashType[prop]; + } + } + } + + if (hash.hasOwnProperty('idBinding')) { + // id can't be bound, so just perform one-time lookup. + hash.id = handlebarsGet(thisContext, hash.idBinding, options); + hashType.id = 'STRING'; + delete hash.idBinding; + delete hashType.idBinding; + } + } + + var ViewHelper = EmberObject.create({ + propertiesFromHTMLOptions: function(options) { + var hash = options.hash; + var data = options.data; + var classes = hash['class']; + + var extensions = { + helperName: options.helperName || '' + }; + + if (hash.id) { + extensions.elementId = hash.id; + } + + if (hash.tag) { + extensions.tagName = hash.tag; + } + + if (classes) { + classes = classes.split(' '); + extensions.classNames = classes; + } + + if (hash.classBinding) { + extensions.classNameBindings = hash.classBinding.split(' '); + } + + if (hash.classNameBindings) { + if (extensions.classNameBindings === undefined) { + extensions.classNameBindings = []; + } + extensions.classNameBindings = extensions.classNameBindings.concat(hash.classNameBindings.split(' ')); + } + + if (hash.attributeBindings) { + extensions.attributeBindings = null; + } + + // Set the proper context for all bindings passed to the helper. This applies to regular attribute bindings + // as well as class name bindings. If the bindings are local, make them relative to the current context + // instead of the view. + var path; + var hashKeys = keys(hash); + + for (var i = 0, l = hashKeys.length; i < l; i++) { + var prop = hashKeys[i]; + var isBinding = IS_BINDING.test(prop); + + if (prop !== 'classNameBindings') { + extensions[prop] = hash[prop]; + } + + // Test if the property ends in "Binding" + if (isBinding && typeof extensions[prop] === 'string') { + path = this.contextualizeBindingPath(hash[prop], data); + if (path) { + extensions[prop] = path; + } + } + } + + if (extensions.classNameBindings) { + // Evaluate the context of class name bindings: + for (var j = 0, k = extensions.classNameBindings.length; j < k; j++) { + var full = extensions.classNameBindings[j]; + + if (typeof full === 'string') { + // Contextualize the path of classNameBinding so this: + // + // classNameBinding="isGreen:green" + // + // is converted to this: + // + // classNameBinding="_parentView.context.isGreen:green" + var parsedPath = View._parsePropertyPath(full); + if (parsedPath.path !== '') { + path = this.contextualizeBindingPath(parsedPath.path, data); + if (path) { + extensions.classNameBindings[j] = path + parsedPath.classNames; + } + } + } + } + } + + return extensions; + }, + + // Transform bindings from the current context to a context that can be evaluated within the view. + // Returns null if the path shouldn't be changed. + // + // TODO: consider the addition of a prefix that would allow this method to return `path`. + contextualizeBindingPath: function(path, data) { + var normalized = normalizePath(null, path, data); + if (normalized.isKeyword) { + return 'templateData.keywords.' + path; + } else if (isGlobalPath(path)) { + return null; + } else if (path === 'this' || path === '') { + return '_parentView.context'; + } else { + return '_parentView.context.' + path; + } + }, + + helper: function(thisContext, path, options) { + var data = options.data; + var fn = options.fn; + var newView; + + makeBindings(thisContext, options); + + var container = this.container || (data && data.view && data.view.container); + newView = handlebarsGetView(thisContext, path, container, options); + + var viewOptions = this.propertiesFromHTMLOptions(options, thisContext); + var currentView = data.view; + viewOptions.templateData = data; + var newViewProto = newView.proto(); + + if (fn) { + viewOptions.template = fn; + } + + // We only want to override the `_context` computed property if there is + // no specified controller. See View#_context for more information. + if (!newViewProto.controller && !newViewProto.controllerBinding && !viewOptions.controller && !viewOptions.controllerBinding) { + viewOptions._context = thisContext; + } + + currentView.appendChild(newView, viewOptions); + }, + + instanceHelper: function(thisContext, newView, options) { + var data = options.data; + var fn = options.fn; + + makeBindings(thisContext, options); + + + var viewOptions = this.propertiesFromHTMLOptions(options, thisContext); + var currentView = data.view; + viewOptions.templateData = data; + + if (fn) { + viewOptions.template = fn; + } + + // We only want to override the `_context` computed property if there is + // no specified controller. See View#_context for more information. + if (!newView.controller && !newView.controllerBinding && !viewOptions.controller && !viewOptions.controllerBinding) { + viewOptions._context = thisContext; + } + + currentView.appendChild(newView, viewOptions); + } + }); + __exports__.ViewHelper = ViewHelper; + /** + `{{view}}` inserts a new instance of an `Ember.View` into a template passing its + options to the `Ember.View`'s `create` method and using the supplied block as + the view's own template. + + An empty `` and the following template: + + ```handlebars + A span: + {{#view tagName="span"}} + hello. + {{/view}} + ``` + + Will result in HTML structure: + + ```html + + + +
    + A span: + + Hello. + +
    + + ``` + + ### `parentView` setting + + The `parentView` property of the new `Ember.View` instance created through + `{{view}}` will be set to the `Ember.View` instance of the template where + `{{view}}` was called. + + ```javascript + aView = Ember.View.create({ + template: Ember.Handlebars.compile("{{#view}} my parent: {{parentView.elementId}} {{/view}}") + }); + + aView.appendTo('body'); + ``` + + Will result in HTML structure: + + ```html +
    +
    + my parent: ember1 +
    +
    + ``` + + ### Setting CSS id and class attributes + + The HTML `id` attribute can be set on the `{{view}}`'s resulting element with + the `id` option. This option will _not_ be passed to `Ember.View.create`. + + ```handlebars + {{#view tagName="span" id="a-custom-id"}} + hello. + {{/view}} + ``` + + Results in the following HTML structure: + + ```html +
    + + hello. + +
    + ``` + + The HTML `class` attribute can be set on the `{{view}}`'s resulting element + with the `class` or `classNameBindings` options. The `class` option will + directly set the CSS `class` attribute and will not be passed to + `Ember.View.create`. `classNameBindings` will be passed to `create` and use + `Ember.View`'s class name binding functionality: + + ```handlebars + {{#view tagName="span" class="a-custom-class"}} + hello. + {{/view}} + ``` + + Results in the following HTML structure: + + ```html +
    + + hello. + +
    + ``` + + ### Supplying a different view class + + `{{view}}` can take an optional first argument before its supplied options to + specify a path to a custom view class. + + ```handlebars + {{#view "custom"}}{{! will look up App.CustomView }} + hello. + {{/view}} + ``` + + The first argument can also be a relative path accessible from the current + context. + + ```javascript + MyApp = Ember.Application.create({}); + MyApp.OuterView = Ember.View.extend({ + innerViewClass: Ember.View.extend({ + classNames: ['a-custom-view-class-as-property'] + }), + template: Ember.Handlebars.compile('{{#view view.innerViewClass}} hi {{/view}}') + }); + + MyApp.OuterView.create().appendTo('body'); + ``` + + Will result in the following HTML: + + ```html +
    +
    + hi +
    +
    + ``` + + ### Blockless use + + If you supply a custom `Ember.View` subclass that specifies its own template + or provide a `templateName` option to `{{view}}` it can be used without + supplying a block. Attempts to use both a `templateName` option and supply a + block will throw an error. + + ```javascript + var App = Ember.Application.create(); + App.WithTemplateDefinedView = Ember.View.extend({ + templateName: 'defined-template' + }); + ``` + + ```handlebars + {{! application.hbs }} + {{view 'with-template-defined'}} + ``` + + ```handlebars + {{! defined-template.hbs }} + Some content for the defined template view. + ``` + + ### `viewName` property + + You can supply a `viewName` option to `{{view}}`. The `Ember.View` instance + will be referenced as a property of its parent view by this name. + + ```javascript + aView = Ember.View.create({ + template: Ember.Handlebars.compile('{{#view viewName="aChildByName"}} hi {{/view}}') + }); + + aView.appendTo('body'); + aView.get('aChildByName') // the instance of Ember.View created by {{view}} helper + ``` + + @method view + @for Ember.Handlebars.helpers + @param {String} path + @param {Hash} options + @return {String} HTML string + */ + function viewHelper(path, options) { + + // If no path is provided, treat path param as options + // and get an instance of the registered `view:toplevel` + if (path && path.data && path.data.isRenderData) { + options = path; + if (options.data && options.data.view && options.data.view.container) { + path = options.data.view.container.lookupFactory('view:toplevel'); + } else { + path = View; + } + } + + options.helperName = options.helperName || 'view'; + + return ViewHelper.helper(this, path, options); + } + + __exports__.viewHelper = viewHelper; + }); +enifed("ember-handlebars/helpers/yield", + ["ember-metal/core","ember-metal/property_get","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var Ember = __dependency1__["default"]; + // var emberAssert = Ember.assert; + + var get = __dependency2__.get; + + /** + `{{yield}}` denotes an area of a template that will be rendered inside + of another template. It has two main uses: + + ### Use with `layout` + When used in a Handlebars template that is assigned to an `Ember.View` + instance's `layout` property Ember will render the layout template first, + inserting the view's own rendered output at the `{{yield}}` location. + + An empty `` and the following application code: + + ```javascript + AView = Ember.View.extend({ + classNames: ['a-view-with-layout'], + layout: Ember.Handlebars.compile('
    {{yield}}
    '), + template: Ember.Handlebars.compile('I am wrapped') + }); + + aView = AView.create(); + aView.appendTo('body'); + ``` + + Will result in the following HTML output: + + ```html + +
    +
    + I am wrapped +
    +
    + + ``` + + The `yield` helper cannot be used outside of a template assigned to an + `Ember.View`'s `layout` property and will throw an error if attempted. + + ```javascript + BView = Ember.View.extend({ + classNames: ['a-view-with-layout'], + template: Ember.Handlebars.compile('{{yield}}') + }); + + bView = BView.create(); + bView.appendTo('body'); + + // throws + // Uncaught Error: assertion failed: + // You called yield in a template that was not a layout + ``` + + ### Use with Ember.Component + When designing components `{{yield}}` is used to denote where, inside the component's + template, an optional block passed to the component should render: + + ```handlebars + + {{#labeled-textfield value=someProperty}} + First name: + {{/labeled-textfield}} + ``` + + ```handlebars + + + ``` + + Result: + + ```html + + ``` + + @method yield + @for Ember.Handlebars.helpers + @param {Hash} options + @return {String} HTML string + */ + __exports__["default"] = function yieldHelper(options) { + var view = options.data.view; + + while (view && !get(view, 'layout')) { + if (view._contextView) { + view = view._contextView; + } else { + view = get(view, '_parentView'); + } + } + + + view._yield(this, options); + } + }); +enifed("ember-handlebars/loader", + ["ember-handlebars/component_lookup","ember-views/system/jquery","ember-metal/error","ember-runtime/system/lazy_load","ember-handlebars-compiler","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + /*globals Handlebars */ + + var ComponentLookup = __dependency1__["default"]; + var jQuery = __dependency2__["default"]; + var EmberError = __dependency3__["default"]; + var onLoad = __dependency4__.onLoad; + + var EmberHandlebars = __dependency5__["default"]; + + /** + @module ember + @submodule ember-handlebars + */ + + /** + Find templates stored in the head tag as script tags and make them available + to `Ember.CoreView` in the global `Ember.TEMPLATES` object. This will be run + as as jQuery DOM-ready callback. + + Script tags with `text/x-handlebars` will be compiled + with Ember's Handlebars and are suitable for use as a view's template. + Those with type `text/x-raw-handlebars` will be compiled with regular + Handlebars and are suitable for use in views' computed properties. + + @private + @method bootstrap + @for Ember.Handlebars + @static + @param ctx + */ + function bootstrap(ctx) { + var selectors = 'script[type="text/x-handlebars"], script[type="text/x-raw-handlebars"]'; + + jQuery(selectors, ctx) + .each(function() { + // Get a reference to the script tag + var script = jQuery(this); + + var compile = (script.attr('type') === 'text/x-raw-handlebars') ? + jQuery.proxy(Handlebars.compile, Handlebars) : + jQuery.proxy(EmberHandlebars.compile, EmberHandlebars); + // Get the name of the script, used by Ember.View's templateName property. + // First look for data-template-name attribute, then fall back to its + // id if no name is found. + var templateName = script.attr('data-template-name') || script.attr('id') || 'application'; + var template = compile(script.html()); + + // Check if template of same name already exists + if (Ember.TEMPLATES[templateName] !== undefined) { + throw new EmberError('Template named "' + templateName + '" already exists.'); + } + + // For templates which have a name, we save them and then remove them from the DOM + Ember.TEMPLATES[templateName] = template; + + // Remove script tag from DOM + script.remove(); + }); + } + + function _bootstrap() { + bootstrap( jQuery(document) ); + } + + function registerComponentLookup(container) { + container.register('component-lookup:main', ComponentLookup); + } + + /* + We tie this to application.load to ensure that we've at least + attempted to bootstrap at the point that the application is loaded. + + We also tie this to document ready since we're guaranteed that all + the inline templates are present at this point. + + There's no harm to running this twice, since we remove the templates + from the DOM after processing. + */ + + onLoad('Ember.Application', function(Application) { + Application.initializer({ + name: 'domTemplates', + initialize: _bootstrap + }); + + Application.initializer({ + name: 'registerComponentLookup', + after: 'domTemplates', + initialize: registerComponentLookup + }); + }); + + __exports__["default"] = bootstrap; + }); +enifed("ember-handlebars/string", + ["ember-runtime/system/string","exports"], + function(__dependency1__, __exports__) { + "use strict"; + // required so we can extend this object. + var EmberStringUtils = __dependency1__["default"]; + + /** + Mark a string as safe for unescaped output with Handlebars. If you + return HTML from a Handlebars helper, use this function to + ensure Handlebars does not escape the HTML. + + ```javascript + Ember.String.htmlSafe('
    someString
    ') + ``` + + @method htmlSafe + @for Ember.String + @static + @return {Handlebars.SafeString} a string that will not be html escaped by Handlebars + */ + function htmlSafe(str) { + return new Handlebars.SafeString(str); + } + + EmberStringUtils.htmlSafe = htmlSafe; + if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) { + + /** + Mark a string as being safe for unescaped output with Handlebars. + + ```javascript + '
    someString
    '.htmlSafe() + ``` + + See [Ember.String.htmlSafe](/api/classes/Ember.String.html#method_htmlSafe). + + @method htmlSafe + @for String + @return {Handlebars.SafeString} a string that will not be html escaped by Handlebars + */ + String.prototype.htmlSafe = function() { + return htmlSafe(this); + }; + } + + __exports__["default"] = htmlSafe; + }); +enifed("ember-handlebars/views/handlebars_bound_view", + ["ember-handlebars-compiler","ember-metal/core","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/merge","ember-metal/run_loop","ember-metal/computed","ember-views/views/view","ember-views/views/states","ember-handlebars/views/metamorph_view","ember-handlebars/ext","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __exports__) { + "use strict"; + /*globals Handlebars, Metamorph:true */ + /*jshint newcap:false*/ + + + /** + @module ember + @submodule ember-handlebars + */ + + var EmberHandlebars = __dependency1__["default"]; + // EmberHandlebars.SafeString; + var SafeString = EmberHandlebars.SafeString; + + var Ember = __dependency2__["default"]; + // Ember.K + var K = Ember.K; + + var EmberError = __dependency3__["default"]; + var get = __dependency4__.get; + var set = __dependency5__.set; + var merge = __dependency6__["default"]; + var run = __dependency7__["default"]; + var computed = __dependency8__.computed; + var View = __dependency9__["default"]; + var cloneStates = __dependency10__.cloneStates; + var states = __dependency10__.states; + var viewStates = states; + + var _MetamorphView = __dependency11__["default"]; + var handlebarsGet = __dependency12__.handlebarsGet; + var uuid = __dependency13__.uuid; + + function SimpleHandlebarsView(path, pathRoot, isEscaped, templateData) { + this.path = path; + this.pathRoot = pathRoot; + this.isEscaped = isEscaped; + this.templateData = templateData; + this[Ember.GUID_KEY] = uuid(); + this._lastNormalizedValue = undefined; + this.state = 'preRender'; + this.updateId = null; + this._parentView = null; + this.buffer = null; + this._morph = null; + } + + SimpleHandlebarsView.prototype = { + isVirtual: true, + isView: true, + + destroy: function () { + if (this.updateId) { + run.cancel(this.updateId); + this.updateId = null; + } + if (this._parentView) { + this._parentView.removeChild(this); + } + this.morph = null; + this.state = 'destroyed'; + }, + + propertyWillChange: K, + + propertyDidChange: K, + + normalizedValue: function() { + var path = this.path; + var pathRoot = this.pathRoot; + var escape = this.isEscaped; + var result, templateData; + + // Use the pathRoot as the result if no path is provided. This + // happens if the path is `this`, which gets normalized into + // a `pathRoot` of the current Handlebars context and a path + // of `''`. + if (path === '') { + result = pathRoot; + } else { + templateData = this.templateData; + result = handlebarsGet(pathRoot, path, { data: templateData }); + } + + if (!escape && !(result instanceof SafeString)) { + result = new SafeString(result); + } + + return result; + }, + + render: function(buffer) { + var value = this.normalizedValue(); + this._lastNormalizedValue = value; + buffer._element = value; + }, + + rerender: function() { + switch(this.state) { + case 'preRender': + case 'destroyed': + break; + case 'inBuffer': + throw new EmberError("Something you did tried to replace an {{expression}} before it was inserted into the DOM."); + case 'hasElement': + case 'inDOM': + this.updateId = run.scheduleOnce('render', this, 'update'); + break; + } + return this; + }, + + update: function () { + this.updateId = null; + var value = this.normalizedValue(); + // doesn't diff SafeString instances + if (value !== this._lastNormalizedValue) { + this._lastNormalizedValue = value; + this._morph.update(value); + } + }, + + _transitionTo: function(state) { + this.state = state; + } + }; + + states = cloneStates(viewStates); + + merge(states._default, { + rerenderIfNeeded: K + }); + + merge(states.inDOM, { + rerenderIfNeeded: function(view) { + if (view.normalizedValue() !== view._lastNormalizedValue) { + view.rerender(); + } + } + }); + + /** + `Ember._HandlebarsBoundView` is a private view created by the Handlebars + `{{bind}}` helpers that is used to keep track of bound properties. + + Every time a property is bound using a `{{mustache}}`, an anonymous subclass + of `Ember._HandlebarsBoundView` is created with the appropriate sub-template + and context set up. When the associated property changes, just the template + for this view will re-render. + + @class _HandlebarsBoundView + @namespace Ember + @extends Ember._MetamorphView + @private + */ + var _HandlebarsBoundView = _MetamorphView.extend({ + instrumentName: 'boundHandlebars', + + _states: states, + + /** + The function used to determine if the `displayTemplate` or + `inverseTemplate` should be rendered. This should be a function that takes + a value and returns a Boolean. + + @property shouldDisplayFunc + @type Function + @default null + */ + shouldDisplayFunc: null, + + /** + Whether the template rendered by this view gets passed the context object + of its parent template, or gets passed the value of retrieving `path` + from the `pathRoot`. + + For example, this is true when using the `{{#if}}` helper, because the + template inside the helper should look up properties relative to the same + object as outside the block. This would be `false` when used with `{{#with + foo}}` because the template should receive the object found by evaluating + `foo`. + + @property preserveContext + @type Boolean + @default false + */ + preserveContext: false, + + /** + If `preserveContext` is true, this is the object that will be used + to render the template. + + @property previousContext + @type Object + */ + previousContext: null, + + /** + The template to render when `shouldDisplayFunc` evaluates to `true`. + + @property displayTemplate + @type Function + @default null + */ + displayTemplate: null, + + /** + The template to render when `shouldDisplayFunc` evaluates to `false`. + + @property inverseTemplate + @type Function + @default null + */ + inverseTemplate: null, + + + /** + The path to look up on `pathRoot` that is passed to + `shouldDisplayFunc` to determine which template to render. + + In addition, if `preserveContext` is `false,` the object at this path will + be passed to the template when rendering. + + @property path + @type String + @default null + */ + path: null, + + /** + The object from which the `path` will be looked up. Sometimes this is the + same as the `previousContext`, but in cases where this view has been + generated for paths that start with a keyword such as `view` or + `controller`, the path root will be that resolved object. + + @property pathRoot + @type Object + */ + pathRoot: null, + + normalizedValue: function() { + var path = get(this, 'path'); + var pathRoot = get(this, 'pathRoot'); + var valueNormalizer = get(this, 'valueNormalizerFunc'); + var result, templateData; + + // Use the pathRoot as the result if no path is provided. This + // happens if the path is `this`, which gets normalized into + // a `pathRoot` of the current Handlebars context and a path + // of `''`. + if (path === '') { + result = pathRoot; + } else { + templateData = get(this, 'templateData'); + result = handlebarsGet(pathRoot, path, { data: templateData }); + } + + return valueNormalizer ? valueNormalizer(result) : result; + }, + + rerenderIfNeeded: function() { + this.currentState.rerenderIfNeeded(this); + }, + + /** + Determines which template to invoke, sets up the correct state based on + that logic, then invokes the default `Ember.View` `render` implementation. + + This method will first look up the `path` key on `pathRoot`, + then pass that value to the `shouldDisplayFunc` function. If that returns + `true,` the `displayTemplate` function will be rendered to DOM. Otherwise, + `inverseTemplate`, if specified, will be rendered. + + For example, if this `Ember._HandlebarsBoundView` represented the `{{#with + foo}}` helper, it would look up the `foo` property of its context, and + `shouldDisplayFunc` would always return true. The object found by looking + up `foo` would be passed to `displayTemplate`. + + @method render + @param {Ember.RenderBuffer} buffer + */ + render: function(buffer) { + // If not invoked via a triple-mustache ({{{foo}}}), escape + // the content of the template. + var escape = get(this, 'isEscaped'); + + var shouldDisplay = get(this, 'shouldDisplayFunc'); + var preserveContext = get(this, 'preserveContext'); + var context = get(this, 'previousContext'); + + var inverseTemplate = get(this, 'inverseTemplate'); + var displayTemplate = get(this, 'displayTemplate'); + + var result = this.normalizedValue(); + + this._lastNormalizedValue = result; + + // First, test the conditional to see if we should + // render the template or not. + if (shouldDisplay(result)) { + set(this, 'template', displayTemplate); + + // If we are preserving the context (for example, if this + // is an #if block, call the template with the same object. + if (preserveContext) { + set(this, '_context', context); + } else { + // Otherwise, determine if this is a block bind or not. + // If so, pass the specified object to the template + if (displayTemplate) { + set(this, '_context', result); + } else { + // This is not a bind block, just push the result of the + // expression to the render context and return. + if (result === null || result === undefined) { + result = ""; + } else if (!(result instanceof SafeString)) { + result = String(result); + } + + if (escape) { result = Handlebars.Utils.escapeExpression(result); } + buffer.push(result); + return; + } + } + } else if (inverseTemplate) { + set(this, 'template', inverseTemplate); + + if (preserveContext) { + set(this, '_context', context); + } else { + set(this, '_context', result); + } + } else { + set(this, 'template', function() { return ''; }); + } + + return this._super(buffer); + } + }); + + __exports__._HandlebarsBoundView = _HandlebarsBoundView; + __exports__.SimpleHandlebarsView = SimpleHandlebarsView; + }); +enifed("ember-handlebars/views/metamorph_view", + ["ember-metal/core","ember-views/views/core_view","ember-views/views/view","ember-metal/mixin","ember-metal/run_loop","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + /* global Metamorph:true */ + + /*jshint newcap:false*/ + var Ember = __dependency1__["default"]; + // Ember.deprecate + + var CoreView = __dependency2__["default"]; + var View = __dependency3__["default"]; + var Mixin = __dependency4__.Mixin; + var run = __dependency5__["default"]; + + /** + @module ember + @submodule ember-handlebars + */ + + function notifyMutationListeners() { + run.once(View, 'notifyMutationListeners'); + } + + // The `morph` and `outerHTML` properties are internal only + // and not observable. + + /** + @class _Metamorph + @namespace Ember + @private + */ + var _Metamorph = Mixin.create({ + isVirtual: true, + tagName: '', + + instrumentName: 'metamorph', + + init: function() { + this._super(); + } + }); + __exports__._Metamorph = _Metamorph; + /** + @class _MetamorphView + @namespace Ember + @extends Ember.View + @uses Ember._Metamorph + @private + */ + var _MetamorphView = View.extend(_Metamorph); + __exports__._MetamorphView = _MetamorphView; + /** + @class _SimpleMetamorphView + @namespace Ember + @extends Ember.CoreView + @uses Ember._Metamorph + @private + */ + var _SimpleMetamorphView = CoreView.extend(_Metamorph); + __exports__._SimpleMetamorphView = _SimpleMetamorphView;__exports__["default"] = View.extend(_Metamorph); + }); +enifed("ember-metal-views", + ["ember-metal-views/renderer","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Renderer = __dependency1__["default"]; + __exports__.Renderer = Renderer; + }); +enifed("ember-metal-views/renderer", + ["morph","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var DOMHelper = __dependency1__.DOMHelper; + + function Renderer() { + this._uuid = 0; + this._views = new Array(2000); + this._queue = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; + this._parents = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; + this._elements = new Array(17); + this._inserts = {}; + this._dom = new DOMHelper(); + } + + function Renderer_renderTree(_view, _parentView, _insertAt) { + var views = this._views; + views[0] = _view; + var insertAt = _insertAt === undefined ? -1 : _insertAt; + var index = 0; + var total = 1; + var levelBase = _parentView ? _parentView._level+1 : 0; + + var root = _parentView == null ? _view : _parentView._root; + + // if root view has a _morph assigned + var willInsert = !!root._morph; + + var queue = this._queue; + queue[0] = 0; + var length = 1; + + var parentIndex = -1; + var parents = this._parents; + var parent = _parentView || null; + var elements = this._elements; + var element = null; + var contextualElement = null; + var level = 0; + + var view = _view; + var children, i, l, child; + while (length) { + elements[level] = element; + if (!view._morph) { + // ensure props we add are in same order + view._morph = null; + } + view._root = root; + this.uuid(view); + view._level = levelBase + level; + if (view._elementCreated) { + this.remove(view, false, true); + } + + this.willCreateElement(view); + + contextualElement = view._morph && view._morph.contextualElement; + if (!contextualElement && parent && parent._childViewsMorph) { + contextualElement = parent._childViewsMorph.contextualElement; + } + if (!contextualElement && view._didCreateElementWithoutMorph) { + // This code path is only used by createElement and rerender when createElement + // was previously called on a view. + contextualElement = document.body; + } + element = this.createElement(view, contextualElement); + + parents[level++] = parentIndex; + parentIndex = index; + parent = view; + + // enqueue for end + queue[length++] = index; + // enqueue children + children = this.childViews(view); + if (children) { + for (i=children.length-1;i>=0;i--) { + child = children[i]; + index = total++; + views[index] = child; + queue[length++] = index; + view = child; + } + } + + index = queue[--length]; + view = views[index]; + + while (parentIndex === index) { + level--; + view._elementCreated = true; + this.didCreateElement(view); + if (willInsert) { + this.willInsertElement(view); + } + + if (level === 0) { + length--; + break; + } + + parentIndex = parents[level]; + parent = parentIndex === -1 ? _parentView : views[parentIndex]; + this.insertElement(view, parent, element, -1); + index = queue[--length]; + view = views[index]; + element = elements[level]; + elements[level] = null; + } + } + + this.insertElement(view, _parentView, element, insertAt); + + for (i=total-1;i>=0;i--) { + if (willInsert) { + views[i]._elementInserted = true; + this.didInsertElement(views[i]); + } + views[i] = null; + } + + return element; + } + + Renderer.prototype.uuid = function Renderer_uuid(view) { + if (view._uuid === undefined) { + view._uuid = ++this._uuid; + view._renderer = this; + } // else assert(view._renderer === this) + return view._uuid; + }; + + Renderer.prototype.scheduleInsert = + function Renderer_scheduleInsert(view, morph) { + if (view._morph || view._elementCreated) { + throw new Error("You cannot insert a View that has already been rendered"); + } + view._morph = morph; + var viewId = this.uuid(view); + this._inserts[viewId] = this.scheduleRender(this, function() { + this._inserts[viewId] = null; + this.renderTree(view); + }); + }; + + Renderer.prototype.appendTo = + function Renderer_appendTo(view, target) { + var morph = this._dom.appendMorph(target); + this.scheduleInsert(view, morph); + }; + + Renderer.prototype.replaceIn = + function Renderer_replaceIn(view, target) { + var morph = this._dom.createMorph(target, null, null); + this.scheduleInsert(view, morph); + }; + + function Renderer_remove(_view, shouldDestroy, reset) { + var viewId = this.uuid(_view); + + if (this._inserts[viewId]) { + this.cancelRender(this._inserts[viewId]); + this._inserts[viewId] = undefined; + } + + if (!_view._elementCreated) { + return; + } + + var removeQueue = []; + var destroyQueue = []; + var morph = _view._morph; + var idx, len, view, staticChildren, queue, + childViews, i, l, parentView; + + removeQueue.push(_view); + + for (idx=0; idx -1; + }; + + var defineNativeShim = function(nativeFunc, shim) { + if (isNativeFunc(nativeFunc)) { + return nativeFunc; + } + return shim; + }; + + // From: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/map + var map = defineNativeShim(ArrayPrototype.map, function(fun /*, thisp */) { + //"use strict"; + + if (this === void 0 || this === null || typeof fun !== "function") { + throw new TypeError(); + } + + var t = Object(this); + var len = t.length >>> 0; + var res = new Array(len); + var thisp = arguments[1]; + + for (var i = 0; i < len; i++) { + if (i in t) { + res[i] = fun.call(thisp, t[i], i, t); + } + } + + return res; + }); + + // From: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/foreach + var forEach = defineNativeShim(ArrayPrototype.forEach, function(fun /*, thisp */) { + //"use strict"; + + if (this === void 0 || this === null || typeof fun !== "function") { + throw new TypeError(); + } + + var t = Object(this); + var len = t.length >>> 0; + var thisp = arguments[1]; + + for (var i = 0; i < len; i++) { + if (i in t) { + fun.call(thisp, t[i], i, t); + } + } + }); + + var indexOf = defineNativeShim(ArrayPrototype.indexOf, function (obj, fromIndex) { + if (fromIndex === null || fromIndex === undefined) { + fromIndex = 0; + } + else if (fromIndex < 0) { + fromIndex = Math.max(0, this.length + fromIndex); + } + + for (var i = fromIndex, j = this.length; i < j; i++) { + if (this[i] === obj) { + return i; + } + } + return -1; + }); + + var lastIndexOf = defineNativeShim(ArrayPrototype.lastIndexOf, function(obj, fromIndex) { + var len = this.length; + var idx; + + if (fromIndex === undefined) fromIndex = len-1; + else fromIndex = (fromIndex < 0) ? Math.ceil(fromIndex) : Math.floor(fromIndex); + if (fromIndex < 0) fromIndex += len; + + for(idx = fromIndex;idx>=0;idx--) { + if (this[idx] === obj) return idx ; + } + return -1; + }); + + var filter = defineNativeShim(ArrayPrototype.filter, function (fn, context) { + var i, value; + var result = []; + var length = this.length; + + for (i = 0; i < length; i++) { + if (this.hasOwnProperty(i)) { + value = this[i]; + if (fn.call(context, value, i, this)) { + result.push(value); + } + } + } + return result; + }); + + if (Ember.SHIM_ES5) { + ArrayPrototype.map = ArrayPrototype.map || map; + ArrayPrototype.forEach = ArrayPrototype.forEach || forEach; + ArrayPrototype.filter = ArrayPrototype.filter || filter; + ArrayPrototype.indexOf = ArrayPrototype.indexOf || indexOf; + ArrayPrototype.lastIndexOf = ArrayPrototype.lastIndexOf || lastIndexOf; + } + + /** + Array polyfills to support ES5 features in older browsers. + + @namespace Ember + @property ArrayPolyfills + */ + __exports__.map = map; + __exports__.forEach = forEach; + __exports__.filter = filter; + __exports__.indexOf = indexOf; + __exports__.lastIndexOf = lastIndexOf; + }); +enifed("ember-metal/binding", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/observer","ember-metal/run_loop","ember-metal/path_cache","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.Logger, Ember.LOG_BINDINGS, assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var trySet = __dependency3__.trySet; + var guidFor = __dependency4__.guidFor; + var addObserver = __dependency5__.addObserver; + var removeObserver = __dependency5__.removeObserver; + var _suspendObserver = __dependency5__._suspendObserver; + var run = __dependency6__["default"]; + var isGlobalPath = __dependency7__.isGlobal; + + + // ES6TODO: where is Ember.lookup defined? + /** + @module ember-metal + */ + + // .......................................................... + // CONSTANTS + // + + /** + Debug parameter you can turn on. This will log all bindings that fire to + the console. This should be disabled in production code. Note that you + can also enable this from the console or temporarily. + + @property LOG_BINDINGS + @for Ember + @type Boolean + @default false + */ + Ember.LOG_BINDINGS = false || !!Ember.ENV.LOG_BINDINGS; + + /** + Returns true if the provided path is global (e.g., `MyApp.fooController.bar`) + instead of local (`foo.bar.baz`). + + @method isGlobalPath + @for Ember + @private + @param {String} path + @return Boolean + */ + + function getWithGlobals(obj, path) { + return get(isGlobalPath(path) ? Ember.lookup : obj, path); + } + + // .......................................................... + // BINDING + // + + function Binding(toPath, fromPath) { + this._direction = undefined; + this._from = fromPath; + this._to = toPath; + this._readyToSync = undefined; + this._oneWay = undefined; + } + + /** + @class Binding + @namespace Ember + */ + + Binding.prototype = { + /** + This copies the Binding so it can be connected to another object. + + @method copy + @return {Ember.Binding} `this` + */ + copy: function () { + var copy = new Binding(this._to, this._from); + if (this._oneWay) { copy._oneWay = true; } + return copy; + }, + + // .......................................................... + // CONFIG + // + + /** + This will set `from` property path to the specified value. It will not + attempt to resolve this property path to an actual object until you + connect the binding. + + The binding will search for the property path starting at the root object + you pass when you `connect()` the binding. It follows the same rules as + `get()` - see that method for more information. + + @method from + @param {String} path the property path to connect to + @return {Ember.Binding} `this` + */ + from: function(path) { + this._from = path; + return this; + }, + + /** + This will set the `to` property path to the specified value. It will not + attempt to resolve this property path to an actual object until you + connect the binding. + + The binding will search for the property path starting at the root object + you pass when you `connect()` the binding. It follows the same rules as + `get()` - see that method for more information. + + @method to + @param {String|Tuple} path A property path or tuple + @return {Ember.Binding} `this` + */ + to: function(path) { + this._to = path; + return this; + }, + + /** + Configures the binding as one way. A one-way binding will relay changes + on the `from` side to the `to` side, but not the other way around. This + means that if you change the `to` side directly, the `from` side may have + a different value. + + @method oneWay + @return {Ember.Binding} `this` + */ + oneWay: function() { + this._oneWay = true; + return this; + }, + + /** + @method toString + @return {String} string representation of binding + */ + toString: function() { + var oneWay = this._oneWay ? '[oneWay]' : ''; + return "Ember.Binding<" + guidFor(this) + ">(" + this._from + " -> " + this._to + ")" + oneWay; + }, + + // .......................................................... + // CONNECT AND SYNC + // + + /** + Attempts to connect this binding instance so that it can receive and relay + changes. This method will raise an exception if you have not set the + from/to properties yet. + + @method connect + @param {Object} obj The root object for this binding. + @return {Ember.Binding} `this` + */ + connect: function(obj) { + + var fromPath = this._from; + var toPath = this._to; + trySet(obj, toPath, getWithGlobals(obj, fromPath)); + + // add an observer on the object to be notified when the binding should be updated + addObserver(obj, fromPath, this, this.fromDidChange); + + // if the binding is a two-way binding, also set up an observer on the target + if (!this._oneWay) { addObserver(obj, toPath, this, this.toDidChange); } + + this._readyToSync = true; + + return this; + }, + + /** + Disconnects the binding instance. Changes will no longer be relayed. You + will not usually need to call this method. + + @method disconnect + @param {Object} obj The root object you passed when connecting the binding. + @return {Ember.Binding} `this` + */ + disconnect: function(obj) { + + var twoWay = !this._oneWay; + + // remove an observer on the object so we're no longer notified of + // changes that should update bindings. + removeObserver(obj, this._from, this, this.fromDidChange); + + // if the binding is two-way, remove the observer from the target as well + if (twoWay) { removeObserver(obj, this._to, this, this.toDidChange); } + + this._readyToSync = false; // disable scheduled syncs... + return this; + }, + + // .......................................................... + // PRIVATE + // + + /* called when the from side changes */ + fromDidChange: function(target) { + this._scheduleSync(target, 'fwd'); + }, + + /* called when the to side changes */ + toDidChange: function(target) { + this._scheduleSync(target, 'back'); + }, + + _scheduleSync: function(obj, dir) { + var existingDir = this._direction; + + // if we haven't scheduled the binding yet, schedule it + if (existingDir === undefined) { + run.schedule('sync', this, this._sync, obj); + this._direction = dir; + } + + // If both a 'back' and 'fwd' sync have been scheduled on the same object, + // default to a 'fwd' sync so that it remains deterministic. + if (existingDir === 'back' && dir === 'fwd') { + this._direction = 'fwd'; + } + }, + + _sync: function(obj) { + var log = Ember.LOG_BINDINGS; + + // don't synchronize destroyed objects or disconnected bindings + if (obj.isDestroyed || !this._readyToSync) { return; } + + // get the direction of the binding for the object we are + // synchronizing from + var direction = this._direction; + + var fromPath = this._from; + var toPath = this._to; + + this._direction = undefined; + + // if we're synchronizing from the remote object... + if (direction === 'fwd') { + var fromValue = getWithGlobals(obj, this._from); + if (log) { + Ember.Logger.log(' ', this.toString(), '->', fromValue, obj); + } + if (this._oneWay) { + trySet(obj, toPath, fromValue); + } else { + _suspendObserver(obj, toPath, this, this.toDidChange, function () { + trySet(obj, toPath, fromValue); + }); + } + // if we're synchronizing *to* the remote object + } else if (direction === 'back') { + var toValue = get(obj, this._to); + if (log) { + Ember.Logger.log(' ', this.toString(), '<-', toValue, obj); + } + _suspendObserver(obj, fromPath, this, this.fromDidChange, function () { + trySet(isGlobalPath(fromPath) ? Ember.lookup : obj, fromPath, toValue); + }); + } + } + + }; + + function mixinProperties(to, from) { + for (var key in from) { + if (from.hasOwnProperty(key)) { + to[key] = from[key]; + } + } + } + + mixinProperties(Binding, { + + /* + See `Ember.Binding.from`. + + @method from + @static + */ + from: function(from) { + var C = this; + return new C(undefined, from); + }, + + /* + See `Ember.Binding.to`. + + @method to + @static + */ + to: function(to) { + var C = this; + return new C(to, undefined); + }, + + /** + Creates a new Binding instance and makes it apply in a single direction. + A one-way binding will relay changes on the `from` side object (supplied + as the `from` argument) the `to` side, but not the other way around. + This means that if you change the "to" side directly, the "from" side may have + a different value. + + See `Binding.oneWay`. + + @method oneWay + @param {String} from from path. + @param {Boolean} [flag] (Optional) passing nothing here will make the + binding `oneWay`. You can instead pass `false` to disable `oneWay`, making the + binding two way again. + @return {Ember.Binding} `this` + */ + oneWay: function(from, flag) { + var C = this; + return new C(undefined, from).oneWay(flag); + } + + }); + /** + An `Ember.Binding` connects the properties of two objects so that whenever + the value of one property changes, the other property will be changed also. + + ## Automatic Creation of Bindings with `/^*Binding/`-named Properties + + You do not usually create Binding objects directly but instead describe + bindings in your class or object definition using automatic binding + detection. + + Properties ending in a `Binding` suffix will be converted to `Ember.Binding` + instances. The value of this property should be a string representing a path + to another object or a custom binding instance created using Binding helpers + (see "One Way Bindings"): + + ``` + valueBinding: "MyApp.someController.title" + ``` + + This will create a binding from `MyApp.someController.title` to the `value` + property of your object instance automatically. Now the two values will be + kept in sync. + + ## One Way Bindings + + One especially useful binding customization you can use is the `oneWay()` + helper. This helper tells Ember that you are only interested in + receiving changes on the object you are binding from. For example, if you + are binding to a preference and you want to be notified if the preference + has changed, but your object will not be changing the preference itself, you + could do: + + ``` + bigTitlesBinding: Ember.Binding.oneWay("MyApp.preferencesController.bigTitles") + ``` + + This way if the value of `MyApp.preferencesController.bigTitles` changes the + `bigTitles` property of your object will change also. However, if you + change the value of your `bigTitles` property, it will not update the + `preferencesController`. + + One way bindings are almost twice as fast to setup and twice as fast to + execute because the binding only has to worry about changes to one side. + + You should consider using one way bindings anytime you have an object that + may be created frequently and you do not intend to change a property; only + to monitor it for changes (such as in the example above). + + ## Adding Bindings Manually + + All of the examples above show you how to configure a custom binding, but the + result of these customizations will be a binding template, not a fully active + Binding instance. The binding will actually become active only when you + instantiate the object the binding belongs to. It is useful however, to + understand what actually happens when the binding is activated. + + For a binding to function it must have at least a `from` property and a `to` + property. The `from` property path points to the object/key that you want to + bind from while the `to` path points to the object/key you want to bind to. + + When you define a custom binding, you are usually describing the property + you want to bind from (such as `MyApp.someController.value` in the examples + above). When your object is created, it will automatically assign the value + you want to bind `to` based on the name of your binding key. In the + examples above, during init, Ember objects will effectively call + something like this on your binding: + + ```javascript + binding = Ember.Binding.from("valueBinding").to("value"); + ``` + + This creates a new binding instance based on the template you provide, and + sets the to path to the `value` property of the new object. Now that the + binding is fully configured with a `from` and a `to`, it simply needs to be + connected to become active. This is done through the `connect()` method: + + ```javascript + binding.connect(this); + ``` + + Note that when you connect a binding you pass the object you want it to be + connected to. This object will be used as the root for both the from and + to side of the binding when inspecting relative paths. This allows the + binding to be automatically inherited by subclassed objects as well. + + This also allows you to bind between objects using the paths you declare in + `from` and `to`: + + ```javascript + // Example 1 + binding = Ember.Binding.from("App.someObject.value").to("value"); + binding.connect(this); + + // Example 2 + binding = Ember.Binding.from("parentView.value").to("App.someObject.value"); + binding.connect(this); + ``` + + Now that the binding is connected, it will observe both the from and to side + and relay changes. + + If you ever needed to do so (you almost never will, but it is useful to + understand this anyway), you could manually create an active binding by + using the `Ember.bind()` helper method. (This is the same method used by + to setup your bindings on objects): + + ```javascript + Ember.bind(MyApp.anotherObject, "value", "MyApp.someController.value"); + ``` + + Both of these code fragments have the same effect as doing the most friendly + form of binding creation like so: + + ```javascript + MyApp.anotherObject = Ember.Object.create({ + valueBinding: "MyApp.someController.value", + + // OTHER CODE FOR THIS OBJECT... + }); + ``` + + Ember's built in binding creation method makes it easy to automatically + create bindings for you. You should always use the highest-level APIs + available, even if you understand how it works underneath. + + @class Binding + @namespace Ember + @since Ember 0.9 + */ + // Ember.Binding = Binding; ES6TODO: where to put this? + + + /** + Global helper method to create a new binding. Just pass the root object + along with a `to` and `from` path to create and connect the binding. + + @method bind + @for Ember + @param {Object} obj The root object of the transform. + @param {String} to The path to the 'to' side of the binding. + Must be relative to obj. + @param {String} from The path to the 'from' side of the binding. + Must be relative to obj or a global path. + @return {Ember.Binding} binding instance + */ + function bind(obj, to, from) { + return new Binding(to, from).connect(obj); + } + + __exports__.bind = bind;/** + @method oneWay + @for Ember + @param {Object} obj The root object of the transform. + @param {String} to The path to the 'to' side of the binding. + Must be relative to obj. + @param {String} from The path to the 'from' side of the binding. + Must be relative to obj or a global path. + @return {Ember.Binding} binding instance + */ + function oneWay(obj, to, from) { + return new Binding(to, from).oneWay().connect(obj); + } + + __exports__.oneWay = oneWay;__exports__.Binding = Binding; + __exports__.isGlobalPath = isGlobalPath; + }); +enifed("ember-metal/cache", + ["ember-metal/dictionary","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var dictionary = __dependency1__["default"]; + __exports__["default"] = Cache; + + function Cache(limit, func) { + this.store = dictionary(null); + this.size = 0; + this.misses = 0; + this.hits = 0; + this.limit = limit; + this.func = func; + } + + var FALSE = function() { }; + var ZERO = function() { }; + var UNDEFINED = function() { }; + var NULL = function() { }; + + Cache.prototype = { + set: function(key, value) { + if (this.limit > this.size) { + this.size ++; + if (value === undefined) { + this.store[key] = UNDEFINED; + } else { + this.store[key] = value; + } + } + + return value; + }, + + get: function(key) { + var value = this.store[key]; + + if (value === undefined) { + this.misses ++; + value = this.set(key, this.func(key)); + } else if (value === UNDEFINED) { + this.hits ++; + value = undefined; + } else { + this.hits ++; + // nothing to translate + } + + return value; + }, + + purge: function() { + this.store = dictionary(null); + this.size = 0; + this.hits = 0; + this.misses = 0; + } + }; + }); +enifed("ember-metal/chains", + ["ember-metal/core","ember-metal/property_get","ember-metal/utils","ember-metal/array","ember-metal/watch_key","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // warn, assert, etc; + var get = __dependency2__.get; + var normalizeTuple = __dependency2__.normalizeTuple; + var meta = __dependency3__.meta; + var forEach = __dependency4__.forEach; + var watchKey = __dependency5__.watchKey; + var unwatchKey = __dependency5__.unwatchKey; + + var metaFor = meta; + var warn = Ember.warn; + var FIRST_KEY = /^([^\.]+)/; + + function firstKey(path) { + return path.match(FIRST_KEY)[0]; + } + + var pendingQueue = []; + + // attempts to add the pendingQueue chains again. If some of them end up + // back in the queue and reschedule is true, schedules a timeout to try + // again. + function flushPendingChains() { + if (pendingQueue.length === 0) { return; } // nothing to do + + var queue = pendingQueue; + pendingQueue = []; + + forEach.call(queue, function(q) { q[0].add(q[1]); }); + + warn('Watching an undefined global, Ember expects watched globals to be setup by the time the run loop is flushed, check for typos', pendingQueue.length === 0); + } + + __exports__.flushPendingChains = flushPendingChains;function addChainWatcher(obj, keyName, node) { + if (!obj || ('object' !== typeof obj)) { return; } // nothing to do + + var m = metaFor(obj); + var nodes = m.chainWatchers; + + if (!m.hasOwnProperty('chainWatchers')) { + nodes = m.chainWatchers = {}; + } + + if (!nodes[keyName]) { nodes[keyName] = []; } + nodes[keyName].push(node); + watchKey(obj, keyName, m); + } + + function removeChainWatcher(obj, keyName, node) { + if (!obj || 'object' !== typeof obj) { return; } // nothing to do + + var m = obj['__ember_meta__']; + if (m && !m.hasOwnProperty('chainWatchers')) { return; } // nothing to do + + var nodes = m && m.chainWatchers; + + if (nodes && nodes[keyName]) { + nodes = nodes[keyName]; + for (var i = 0, l = nodes.length; i < l; i++) { + if (nodes[i] === node) { + nodes.splice(i, 1); + break; + } + } + } + unwatchKey(obj, keyName, m); + } + + // A ChainNode watches a single key on an object. If you provide a starting + // value for the key then the node won't actually watch it. For a root node + // pass null for parent and key and object for value. + function ChainNode(parent, key, value) { + this._parent = parent; + this._key = key; + + // _watching is true when calling get(this._parent, this._key) will + // return the value of this node. + // + // It is false for the root of a chain (because we have no parent) + // and for global paths (because the parent node is the object with + // the observer on it) + this._watching = value===undefined; + + this._value = value; + this._paths = {}; + if (this._watching) { + this._object = parent.value(); + if (this._object) { addChainWatcher(this._object, this._key, this); } + } + + // Special-case: the EachProxy relies on immediate evaluation to + // establish its observers. + // + // TODO: Replace this with an efficient callback that the EachProxy + // can implement. + if (this._parent && this._parent._key === '@each') { + this.value(); + } + } + + var ChainNodePrototype = ChainNode.prototype; + + function lazyGet(obj, key) { + if (!obj) return undefined; + + var meta = obj['__ember_meta__']; + // check if object meant only to be a prototype + if (meta && meta.proto === obj) return undefined; + + if (key === "@each") return get(obj, key); + + // if a CP only return cached value + var desc = meta && meta.descs[key]; + if (desc && desc._cacheable) { + if (key in meta.cache) { + return meta.cache[key]; + } else { + return undefined; + } + } + + return get(obj, key); + } + + ChainNodePrototype.value = function() { + if (this._value === undefined && this._watching) { + var obj = this._parent.value(); + this._value = lazyGet(obj, this._key); + } + return this._value; + }; + + ChainNodePrototype.destroy = function() { + if (this._watching) { + var obj = this._object; + if (obj) { removeChainWatcher(obj, this._key, this); } + this._watching = false; // so future calls do nothing + } + }; + + // copies a top level object only + ChainNodePrototype.copy = function(obj) { + var ret = new ChainNode(null, null, obj); + var paths = this._paths; + var path; + + for (path in paths) { + if (paths[path] <= 0) { continue; } // this check will also catch non-number vals. + ret.add(path); + } + return ret; + }; + + // called on the root node of a chain to setup watchers on the specified + // path. + ChainNodePrototype.add = function(path) { + var obj, tuple, key, src, paths; + + paths = this._paths; + paths[path] = (paths[path] || 0) + 1; + + obj = this.value(); + tuple = normalizeTuple(obj, path); + + // the path was a local path + if (tuple[0] && tuple[0] === obj) { + path = tuple[1]; + key = firstKey(path); + path = path.slice(key.length+1); + + // global path, but object does not exist yet. + // put into a queue and try to connect later. + } else if (!tuple[0]) { + pendingQueue.push([this, path]); + tuple.length = 0; + return; + + // global path, and object already exists + } else { + src = tuple[0]; + key = path.slice(0, 0-(tuple[1].length+1)); + path = tuple[1]; + } + + tuple.length = 0; + this.chain(key, path, src); + }; + + // called on the root node of a chain to teardown watcher on the specified + // path + ChainNodePrototype.remove = function(path) { + var obj, tuple, key, src, paths; + + paths = this._paths; + if (paths[path] > 0) { paths[path]--; } + + obj = this.value(); + tuple = normalizeTuple(obj, path); + if (tuple[0] === obj) { + path = tuple[1]; + key = firstKey(path); + path = path.slice(key.length+1); + } else { + src = tuple[0]; + key = path.slice(0, 0-(tuple[1].length+1)); + path = tuple[1]; + } + + tuple.length = 0; + this.unchain(key, path); + }; + + ChainNodePrototype.count = 0; + + ChainNodePrototype.chain = function(key, path, src) { + var chains = this._chains; + var node; + if (!chains) { chains = this._chains = {}; } + + node = chains[key]; + if (!node) { node = chains[key] = new ChainNode(this, key, src); } + node.count++; // count chains... + + // chain rest of path if there is one + if (path) { + key = firstKey(path); + path = path.slice(key.length+1); + node.chain(key, path); // NOTE: no src means it will observe changes... + } + }; + + ChainNodePrototype.unchain = function(key, path) { + var chains = this._chains; + var node = chains[key]; + + // unchain rest of path first... + if (path && path.length>1) { + key = firstKey(path); + path = path.slice(key.length+1); + node.unchain(key, path); + } + + // delete node if needed. + node.count--; + if (node.count<=0) { + delete chains[node._key]; + node.destroy(); + } + + }; + + ChainNodePrototype.willChange = function(events) { + var chains = this._chains; + if (chains) { + for(var key in chains) { + if (!chains.hasOwnProperty(key)) { continue; } + chains[key].willChange(events); + } + } + + if (this._parent) { this._parent.chainWillChange(this, this._key, 1, events); } + }; + + ChainNodePrototype.chainWillChange = function(chain, path, depth, events) { + if (this._key) { path = this._key + '.' + path; } + + if (this._parent) { + this._parent.chainWillChange(this, path, depth+1, events); + } else { + if (depth > 1) { + events.push(this.value(), path); + } + path = 'this.' + path; + if (this._paths[path] > 0) { + events.push(this.value(), path); + } + } + }; + + ChainNodePrototype.chainDidChange = function(chain, path, depth, events) { + if (this._key) { path = this._key + '.' + path; } + if (this._parent) { + this._parent.chainDidChange(this, path, depth+1, events); + } else { + if (depth > 1) { + events.push(this.value(), path); + } + path = 'this.' + path; + if (this._paths[path] > 0) { + events.push(this.value(), path); + } + } + }; + + ChainNodePrototype.didChange = function(events) { + // invalidate my own value first. + if (this._watching) { + var obj = this._parent.value(); + if (obj !== this._object) { + removeChainWatcher(this._object, this._key, this); + this._object = obj; + addChainWatcher(obj, this._key, this); + } + this._value = undefined; + + // Special-case: the EachProxy relies on immediate evaluation to + // establish its observers. + if (this._parent && this._parent._key === '@each') + this.value(); + } + + // then notify chains... + var chains = this._chains; + if (chains) { + for(var key in chains) { + if (!chains.hasOwnProperty(key)) { continue; } + chains[key].didChange(events); + } + } + + // if no events are passed in then we only care about the above wiring update + if (events === null) { return; } + + // and finally tell parent about my path changing... + if (this._parent) { this._parent.chainDidChange(this, this._key, 1, events); } + }; + + function finishChains(obj) { + // We only create meta if we really have to + var m = obj['__ember_meta__'], + chains, chainWatchers, chainNodes; + if (m) { + // finish any current chains node watchers that reference obj + chainWatchers = m.chainWatchers; + if (chainWatchers) { + for(var key in chainWatchers) { + if (!chainWatchers.hasOwnProperty(key)) { continue; } + chainNodes = chainWatchers[key]; + if (chainNodes) { + for (var i=0,l=chainNodes.length;i 1) { + args = a_slice.call(arguments); + func = args.pop(); + } + + if (typeof func !== "function") { + throw new EmberError("Computed Property declared without a property function"); + } + + var cp = new ComputedProperty(func); + + if (args) { + cp.property.apply(cp, args); + } + + return cp; + } + + /** + Returns the cached value for a property, if one exists. + This can be useful for peeking at the value of a computed + property that is generated lazily, without accidentally causing + it to be created. + + @method cacheFor + @for Ember + @param {Object} obj the object whose property you want to check + @param {String} key the name of the property whose cached value you want + to return + @return {Object} the cached value + */ + function cacheFor(obj, key) { + var meta = obj['__ember_meta__']; + var cache = meta && meta.cache; + var ret = cache && cache[key]; + + if (ret === UNDEFINED) { return undefined; } + return ret; + } + + cacheFor.set = function(cache, key, value) { + if (value === undefined) { + cache[key] = UNDEFINED; + } else { + cache[key] = value; + } + }; + + cacheFor.get = function(cache, key) { + var ret = cache[key]; + if (ret === UNDEFINED) { return undefined; } + return ret; + }; + + cacheFor.remove = function(cache, key) { + cache[key] = undefined; + }; + + __exports__.ComputedProperty = ComputedProperty; + __exports__.computed = computed; + __exports__.cacheFor = cacheFor; + }); +enifed("ember-metal/computed_macros", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/computed","ember-metal/is_empty","ember-metal/is_none","ember-metal/alias"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__) { + "use strict"; + var Ember = __dependency1__["default"]; + var get = __dependency2__.get; + var set = __dependency3__.set; + var computed = __dependency4__.computed; + var isEmpty = __dependency5__["default"]; + var isNone = __dependency6__.isNone; + var alias = __dependency7__.alias; + + /** + @module ember-metal + */ + + var a_slice = [].slice; + + function getProperties(self, propertyNames) { + var ret = {}; + for(var i = 0; i < propertyNames.length; i++) { + ret[propertyNames[i]] = get(self, propertyNames[i]); + } + return ret; + } + + function registerComputed(name, macro) { + computed[name] = function(dependentKey) { + var args = a_slice.call(arguments); + return computed(dependentKey, function() { + return macro.apply(this, args); + }); + }; + } + + function registerComputedWithProperties(name, macro) { + computed[name] = function() { + var properties = a_slice.call(arguments); + + var computedFunc = computed(function() { + return macro.apply(this, [getProperties(this, properties)]); + }); + + return computedFunc.property.apply(computedFunc, properties); + }; + } + + /** + A computed property that returns true if the value of the dependent + property is null, an empty string, empty array, or empty function. + + Example + + ```javascript + var ToDoList = Ember.Object.extend({ + done: Ember.computed.empty('todos') + }); + + var todoList = ToDoList.create({ + todos: ['Unit Test', 'Documentation', 'Release'] + }); + + todoList.get('done'); // false + todoList.get('todos').clear(); + todoList.get('done'); // true + ``` + + @since 1.6.0 + @method computed.empty + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which negate + the original value for property + */ + computed.empty = function (dependentKey) { + return computed(dependentKey + '.length', function () { + return isEmpty(get(this, dependentKey)); + }); + }; + + /** + A computed property that returns true if the value of the dependent + property is NOT null, an empty string, empty array, or empty function. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + hasStuff: Ember.computed.notEmpty('backpack') + }); + + var hamster = Hamster.create({ backpack: ['Food', 'Sleeping Bag', 'Tent'] }); + + hamster.get('hasStuff'); // true + hamster.get('backpack').clear(); // [] + hamster.get('hasStuff'); // false + ``` + + @method computed.notEmpty + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which returns true if + original value for property is not empty. + */ + computed.notEmpty = function(dependentKey) { + return computed(dependentKey + '.length', function () { + return !isEmpty(get(this, dependentKey)); + }); + }; + + /** + A computed property that returns true if the value of the dependent + property is null or undefined. This avoids errors from JSLint complaining + about use of ==, which can be technically confusing. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + isHungry: Ember.computed.none('food') + }); + + var hamster = Hamster.create(); + + hamster.get('isHungry'); // true + hamster.set('food', 'Banana'); + hamster.get('isHungry'); // false + hamster.set('food', null); + hamster.get('isHungry'); // true + ``` + + @method computed.none + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which + returns true if original value for property is null or undefined. + */ + registerComputed('none', function(dependentKey) { + return isNone(get(this, dependentKey)); + }); + + /** + A computed property that returns the inverse boolean value + of the original value for the dependent property. + + Example + + ```javascript + var User = Ember.Object.extend({ + isAnonymous: Ember.computed.not('loggedIn') + }); + + var user = User.create({loggedIn: false}); + + user.get('isAnonymous'); // true + user.set('loggedIn', true); + user.get('isAnonymous'); // false + ``` + + @method computed.not + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which returns + inverse of the original value for property + */ + registerComputed('not', function(dependentKey) { + return !get(this, dependentKey); + }); + + /** + A computed property that converts the provided dependent property + into a boolean value. + + ```javascript + var Hamster = Ember.Object.extend({ + hasBananas: Ember.computed.bool('numBananas') + }); + + var hamster = Hamster.create(); + + hamster.get('hasBananas'); // false + hamster.set('numBananas', 0); + hamster.get('hasBananas'); // false + hamster.set('numBananas', 1); + hamster.get('hasBananas'); // true + hamster.set('numBananas', null); + hamster.get('hasBananas'); // false + ``` + + @method computed.bool + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which converts + to boolean the original value for property + */ + registerComputed('bool', function(dependentKey) { + return !!get(this, dependentKey); + }); + + /** + A computed property which matches the original value for the + dependent property against a given RegExp, returning `true` + if they values matches the RegExp and `false` if it does not. + + Example + + ```javascript + var User = Ember.Object.extend({ + hasValidEmail: Ember.computed.match('email', /^.+@.+\..+$/) + }); + + var user = User.create({loggedIn: false}); + + user.get('hasValidEmail'); // false + user.set('email', ''); + user.get('hasValidEmail'); // false + user.set('email', 'ember_hamster@example.com'); + user.get('hasValidEmail'); // true + ``` + + @method computed.match + @for Ember + @param {String} dependentKey + @param {RegExp} regexp + @return {Ember.ComputedProperty} computed property which match + the original value for property against a given RegExp + */ + registerComputed('match', function(dependentKey, regexp) { + var value = get(this, dependentKey); + return typeof value === 'string' ? regexp.test(value) : false; + }); + + /** + A computed property that returns true if the provided dependent property + is equal to the given value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + napTime: Ember.computed.equal('state', 'sleepy') + }); + + var hamster = Hamster.create(); + + hamster.get('napTime'); // false + hamster.set('state', 'sleepy'); + hamster.get('napTime'); // true + hamster.set('state', 'hungry'); + hamster.get('napTime'); // false + ``` + + @method computed.equal + @for Ember + @param {String} dependentKey + @param {String|Number|Object} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is equal to the given value. + */ + registerComputed('equal', function(dependentKey, value) { + return get(this, dependentKey) === value; + }); + + /** + A computed property that returns true if the provided dependent property + is greater than the provided value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + hasTooManyBananas: Ember.computed.gt('numBananas', 10) + }); + + var hamster = Hamster.create(); + + hamster.get('hasTooManyBananas'); // false + hamster.set('numBananas', 3); + hamster.get('hasTooManyBananas'); // false + hamster.set('numBananas', 11); + hamster.get('hasTooManyBananas'); // true + ``` + + @method computed.gt + @for Ember + @param {String} dependentKey + @param {Number} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is greater than given value. + */ + registerComputed('gt', function(dependentKey, value) { + return get(this, dependentKey) > value; + }); + + /** + A computed property that returns true if the provided dependent property + is greater than or equal to the provided value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + hasTooManyBananas: Ember.computed.gte('numBananas', 10) + }); + + var hamster = Hamster.create(); + + hamster.get('hasTooManyBananas'); // false + hamster.set('numBananas', 3); + hamster.get('hasTooManyBananas'); // false + hamster.set('numBananas', 10); + hamster.get('hasTooManyBananas'); // true + ``` + + @method computed.gte + @for Ember + @param {String} dependentKey + @param {Number} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is greater or equal then given value. + */ + registerComputed('gte', function(dependentKey, value) { + return get(this, dependentKey) >= value; + }); + + /** + A computed property that returns true if the provided dependent property + is less than the provided value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + needsMoreBananas: Ember.computed.lt('numBananas', 3) + }); + + var hamster = Hamster.create(); + + hamster.get('needsMoreBananas'); // true + hamster.set('numBananas', 3); + hamster.get('needsMoreBananas'); // false + hamster.set('numBananas', 2); + hamster.get('needsMoreBananas'); // true + ``` + + @method computed.lt + @for Ember + @param {String} dependentKey + @param {Number} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is less then given value. + */ + registerComputed('lt', function(dependentKey, value) { + return get(this, dependentKey) < value; + }); + + /** + A computed property that returns true if the provided dependent property + is less than or equal to the provided value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + needsMoreBananas: Ember.computed.lte('numBananas', 3) + }); + + var hamster = Hamster.create(); + + hamster.get('needsMoreBananas'); // true + hamster.set('numBananas', 5); + hamster.get('needsMoreBananas'); // false + hamster.set('numBananas', 3); + hamster.get('needsMoreBananas'); // true + ``` + + @method computed.lte + @for Ember + @param {String} dependentKey + @param {Number} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is less or equal than given value. + */ + registerComputed('lte', function(dependentKey, value) { + return get(this, dependentKey) <= value; + }); + + /** + A computed property that performs a logical `and` on the + original values for the provided dependent properties. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + readyForCamp: Ember.computed.and('hasTent', 'hasBackpack') + }); + + var hamster = Hamster.create(); + + hamster.get('readyForCamp'); // false + hamster.set('hasTent', true); + hamster.get('readyForCamp'); // false + hamster.set('hasBackpack', true); + hamster.get('readyForCamp'); // true + ``` + + @method computed.and + @for Ember + @param {String} dependentKey* + @return {Ember.ComputedProperty} computed property which performs + a logical `and` on the values of all the original values for properties. + */ + registerComputedWithProperties('and', function(properties) { + for (var key in properties) { + if (properties.hasOwnProperty(key) && !properties[key]) { + return false; + } + } + return true; + }); + + /** + A computed property which performs a logical `or` on the + original values for the provided dependent properties. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + readyForRain: Ember.computed.or('hasJacket', 'hasUmbrella') + }); + + var hamster = Hamster.create(); + + hamster.get('readyForRain'); // false + hamster.set('hasJacket', true); + hamster.get('readyForRain'); // true + ``` + + @method computed.or + @for Ember + @param {String} dependentKey* + @return {Ember.ComputedProperty} computed property which performs + a logical `or` on the values of all the original values for properties. + */ + registerComputedWithProperties('or', function(properties) { + for (var key in properties) { + if (properties.hasOwnProperty(key) && properties[key]) { + return true; + } + } + return false; + }); + + /** + A computed property that returns the first truthy value + from a list of dependent properties. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + hasClothes: Ember.computed.any('hat', 'shirt') + }); + + var hamster = Hamster.create(); + + hamster.get('hasClothes'); // null + hamster.set('shirt', 'Hawaiian Shirt'); + hamster.get('hasClothes'); // 'Hawaiian Shirt' + ``` + + @method computed.any + @for Ember + @param {String} dependentKey* + @return {Ember.ComputedProperty} computed property which returns + the first truthy value of given list of properties. + */ + registerComputedWithProperties('any', function(properties) { + for (var key in properties) { + if (properties.hasOwnProperty(key) && properties[key]) { + return properties[key]; + } + } + return null; + }); + + /** + A computed property that returns the array of values + for the provided dependent properties. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + clothes: Ember.computed.collect('hat', 'shirt') + }); + + var hamster = Hamster.create(); + + hamster.get('clothes'); // [null, null] + hamster.set('hat', 'Camp Hat'); + hamster.set('shirt', 'Camp Shirt'); + hamster.get('clothes'); // ['Camp Hat', 'Camp Shirt'] + ``` + + @method computed.collect + @for Ember + @param {String} dependentKey* + @return {Ember.ComputedProperty} computed property which maps + values of all passed in properties to an array. + */ + registerComputedWithProperties('collect', function(properties) { + var res = []; + for (var key in properties) { + if (properties.hasOwnProperty(key)) { + if (isNone(properties[key])) { + res.push(null); + } else { + res.push(properties[key]); + } + } + } + return res; + }); + + /** + Creates a new property that is an alias for another property + on an object. Calls to `get` or `set` this property behave as + though they were called on the original property. + + ```javascript + var Person = Ember.Object.extend({ + name: 'Alex Matchneer', + nomen: Ember.computed.alias('name') + }); + + var alex = Person.create(); + + alex.get('nomen'); // 'Alex Matchneer' + alex.get('name'); // 'Alex Matchneer' + + alex.set('nomen', '@machty'); + alex.get('name'); // '@machty' + ``` + + @method computed.alias + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which creates an + alias to the original value for property. + */ + computed.alias = alias; + + /** + Where `computed.alias` aliases `get` and `set`, and allows for bidirectional + data flow, `computed.oneWay` only provides an aliased `get`. The `set` will + not mutate the upstream property, rather causes the current property to + become the value set. This causes the downstream property to permanently + diverge from the upstream property. + + Example + + ```javascript + var User = Ember.Object.extend({ + firstName: null, + lastName: null, + nickName: Ember.computed.oneWay('firstName') + }); + + var teddy = User.create({ + firstName: 'Teddy', + lastName: 'Zeenny' + }); + + teddy.get('nickName'); // 'Teddy' + teddy.set('nickName', 'TeddyBear'); // 'TeddyBear' + teddy.get('firstName'); // 'Teddy' + ``` + + @method computed.oneWay + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which creates a + one way computed property to the original value for property. + */ + computed.oneWay = function(dependentKey) { + return alias(dependentKey).oneWay(); + }; + + /** + This is a more semantically meaningful alias of `computed.oneWay`, + whose name is somewhat ambiguous as to which direction the data flows. + + @method computed.reads + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which creates a + one way computed property to the original value for property. + */ + computed.reads = computed.oneWay; + + /** + Where `computed.oneWay` provides oneWay bindings, `computed.readOnly` provides + a readOnly one way binding. Very often when using `computed.oneWay` one does + not also want changes to propogate back up, as they will replace the value. + + This prevents the reverse flow, and also throws an exception when it occurs. + + Example + + ```javascript + var User = Ember.Object.extend({ + firstName: null, + lastName: null, + nickName: Ember.computed.readOnly('firstName') + }); + + var teddy = User.create({ + firstName: 'Teddy', + lastName: 'Zeenny' + }); + + teddy.get('nickName'); // 'Teddy' + teddy.set('nickName', 'TeddyBear'); // throws Exception + // throw new Ember.Error('Cannot Set: nickName on: ' );` + teddy.get('firstName'); // 'Teddy' + ``` + + @method computed.readOnly + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which creates a + one way computed property to the original value for property. + @since 1.5.0 + */ + computed.readOnly = function(dependentKey) { + return alias(dependentKey).readOnly(); + }; + /** + A computed property that acts like a standard getter and setter, + but returns the value at the provided `defaultPath` if the + property itself has not been set to a value + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + wishList: Ember.computed.defaultTo('favoriteFood') + }); + + var hamster = Hamster.create({ favoriteFood: 'Banana' }); + + hamster.get('wishList'); // 'Banana' + hamster.set('wishList', 'More Unit Tests'); + hamster.get('wishList'); // 'More Unit Tests' + hamster.get('favoriteFood'); // 'Banana' + ``` + + @method computed.defaultTo + @for Ember + @param {String} defaultPath + @return {Ember.ComputedProperty} computed property which acts like + a standard getter and setter, but defaults to the value from `defaultPath`. + @deprecated Use `Ember.computed.oneWay` or custom CP with default instead. + */ + // ES6TODO: computed should have its own export path so you can do import {defaultTo} from computed + computed.defaultTo = function(defaultPath) { + return computed(function(key, newValue, cachedValue) { + + if (arguments.length === 1) { + return get(this, defaultPath); + } + return newValue != null ? newValue : get(this, defaultPath); + }); + }; + + /** + Creates a new property that is an alias for another property + on an object. Calls to `get` or `set` this property behave as + though they were called on the original property, but also + print a deprecation warning. + + @method computed.deprecatingAlias + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which creates an + alias with a deprecation to the original value for property. + @since 1.7.0 + */ + computed.deprecatingAlias = function(dependentKey) { + return computed(dependentKey, function(key, value) { + + if (arguments.length > 1) { + set(this, dependentKey, value); + return value; + } else { + return get(this, dependentKey); + } + }); + }; + }); +enifed("ember-metal/core", + ["exports"], + function(__exports__) { + "use strict"; + /*globals Ember:true,Em:true,ENV,EmberENV,MetamorphENV:true */ + + /** + @module ember + @submodule ember-metal + */ + + /** + All Ember methods and functions are defined inside of this namespace. You + generally should not add new properties to this namespace as it may be + overwritten by future versions of Ember. + + You can also use the shorthand `Em` instead of `Ember`. + + Ember-Runtime is a framework that provides core functions for Ember including + cross-platform functions, support for property observing and objects. Its + focus is on small size and performance. You can use this in place of or + along-side other cross-platform libraries such as jQuery. + + The core Runtime framework is based on the jQuery API with a number of + performance optimizations. + + @class Ember + @static + @version 1.8.0 + */ + + if ('undefined' === typeof Ember) { + // Create core object. Make it act like an instance of Ember.Namespace so that + // objects assigned to it are given a sane string representation. + Ember = {}; + } + + // Default imports, exports and lookup to the global object; + var imports = Ember.imports = Ember.imports || this; + var exports = Ember.exports = Ember.exports || this; + var lookup = Ember.lookup = Ember.lookup || this; + + // aliases needed to keep minifiers from removing the global context + exports.Em = exports.Ember = Ember; + + // Make sure these are set whether Ember was already defined or not + + Ember.isNamespace = true; + + Ember.toString = function() { return "Ember"; }; + + + /** + @property VERSION + @type String + @default '1.8.0' + @static + */ + Ember.VERSION = '1.8.0'; + + /** + Standard environmental variables. You can define these in a global `EmberENV` + variable before loading Ember to control various configuration settings. + + For backwards compatibility with earlier versions of Ember the global `ENV` + variable will be used if `EmberENV` is not defined. + + @property ENV + @type Hash + */ + + if (Ember.ENV) { + // do nothing if Ember.ENV is already setup + } else if ('undefined' !== typeof EmberENV) { + Ember.ENV = EmberENV; + } else if('undefined' !== typeof ENV) { + Ember.ENV = ENV; + } else { + Ember.ENV = {}; + } + + Ember.config = Ember.config || {}; + + // We disable the RANGE API by default for performance reasons + if ('undefined' === typeof Ember.ENV.DISABLE_RANGE_API) { + Ember.ENV.DISABLE_RANGE_API = true; + } + + if ("undefined" === typeof MetamorphENV) { + exports.MetamorphENV = {}; + } + + MetamorphENV.DISABLE_RANGE_API = Ember.ENV.DISABLE_RANGE_API; + + /** + Hash of enabled Canary features. Add to this before creating your application. + + You can also define `ENV.FEATURES` if you need to enable features flagged at runtime. + + @class FEATURES + @namespace Ember + @static + @since 1.1.0 + */ + + Ember.FEATURES = Ember.ENV.FEATURES || {}; + + /** + Test that a feature is enabled. Parsed by Ember's build tools to leave + experimental features out of beta/stable builds. + + You can define the following configuration options: + + * `ENV.ENABLE_ALL_FEATURES` - force all features to be enabled. + * `ENV.ENABLE_OPTIONAL_FEATURES` - enable any features that have not been explicitly + enabled/disabled. + + @method isEnabled + @param {String} feature + @return {Boolean} + @for Ember.FEATURES + @since 1.1.0 + */ + + Ember.FEATURES.isEnabled = function(feature) { + var featureValue = Ember.FEATURES[feature]; + + if (Ember.ENV.ENABLE_ALL_FEATURES) { + return true; + } else if (featureValue === true || featureValue === false || featureValue === undefined) { + return featureValue; + } else if (Ember.ENV.ENABLE_OPTIONAL_FEATURES) { + return true; + } else { + return false; + } + }; + + // .......................................................... + // BOOTSTRAP + // + + /** + Determines whether Ember should enhance some built-in object prototypes to + provide a more friendly API. If enabled, a few methods will be added to + `Function`, `String`, and `Array`. `Object.prototype` will not be enhanced, + which is the one that causes most trouble for people. + + In general we recommend leaving this option set to true since it rarely + conflicts with other code. If you need to turn it off however, you can + define an `ENV.EXTEND_PROTOTYPES` config to disable it. + + @property EXTEND_PROTOTYPES + @type Boolean + @default true + @for Ember + */ + Ember.EXTEND_PROTOTYPES = Ember.ENV.EXTEND_PROTOTYPES; + + if (typeof Ember.EXTEND_PROTOTYPES === 'undefined') { + Ember.EXTEND_PROTOTYPES = true; + } + + /** + Determines whether Ember logs a full stack trace during deprecation warnings + + @property LOG_STACKTRACE_ON_DEPRECATION + @type Boolean + @default true + */ + Ember.LOG_STACKTRACE_ON_DEPRECATION = (Ember.ENV.LOG_STACKTRACE_ON_DEPRECATION !== false); + + /** + Determines whether Ember should add ECMAScript 5 shims to older browsers. + + @property SHIM_ES5 + @type Boolean + @default Ember.EXTEND_PROTOTYPES + */ + Ember.SHIM_ES5 = (Ember.ENV.SHIM_ES5 === false) ? false : Ember.EXTEND_PROTOTYPES; + + /** + Determines whether Ember logs info about version of used libraries + + @property LOG_VERSION + @type Boolean + @default true + */ + Ember.LOG_VERSION = (Ember.ENV.LOG_VERSION === false) ? false : true; + + /** + Empty function. Useful for some operations. Always returns `this`. + + @method K + @private + @return {Object} + */ + var K = function() { return this; }; + var K = K; + __exports__.K = K;Ember.K = K; + //TODO: ES6 GLOBL TODO + + // Stub out the methods defined by the ember-debug package in case it's not loaded + + if ('undefined' === typeof Ember.assert) { Ember.assert = Ember.K; } + if ('undefined' === typeof Ember.warn) { Ember.warn = Ember.K; } + if ('undefined' === typeof Ember.debug) { Ember.debug = Ember.K; } + if ('undefined' === typeof Ember.runInDebug) { Ember.runInDebug = Ember.K; } + if ('undefined' === typeof Ember.deprecate) { Ember.deprecate = Ember.K; } + if ('undefined' === typeof Ember.deprecateFunc) { + Ember.deprecateFunc = function(_, func) { return func; }; + } + + __exports__["default"] = Ember; + }); +enifed("ember-metal/dependent_keys", + ["ember-metal/platform","ember-metal/watching","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var create = __dependency1__.create; + var watch = __dependency2__.watch; + var unwatch = __dependency2__.unwatch; + + /** + @module ember-metal + */ + + var o_create = create; + + // .......................................................... + // DEPENDENT KEYS + // + + // data structure: + // meta.deps = { + // 'depKey': { + // 'keyName': count, + // } + // } + + /* + This function returns a map of unique dependencies for a + given object and key. + */ + function keysForDep(depsMeta, depKey) { + var keys = depsMeta[depKey]; + if (!keys) { + // if there are no dependencies yet for a the given key + // create a new empty list of dependencies for the key + keys = depsMeta[depKey] = {}; + } else if (!depsMeta.hasOwnProperty(depKey)) { + // otherwise if the dependency list is inherited from + // a superclass, clone the hash + keys = depsMeta[depKey] = o_create(keys); + } + return keys; + } + + function metaForDeps(meta) { + return keysForDep(meta, 'deps'); + } + + function addDependentKeys(desc, obj, keyName, meta) { + // the descriptor has a list of dependent keys, so + // add all of its dependent keys. + var depKeys = desc._dependentKeys, depsMeta, idx, len, depKey, keys; + if (!depKeys) return; + + depsMeta = metaForDeps(meta); + + for(idx = 0, len = depKeys.length; idx < len; idx++) { + depKey = depKeys[idx]; + // Lookup keys meta for depKey + keys = keysForDep(depsMeta, depKey); + // Increment the number of times depKey depends on keyName. + keys[keyName] = (keys[keyName] || 0) + 1; + // Watch the depKey + watch(obj, depKey, meta); + } + } + + __exports__.addDependentKeys = addDependentKeys;function removeDependentKeys(desc, obj, keyName, meta) { + // the descriptor has a list of dependent keys, so + // remove all of its dependent keys. + var depKeys = desc._dependentKeys, depsMeta, idx, len, depKey, keys; + if (!depKeys) return; + + depsMeta = metaForDeps(meta); + + for(idx = 0, len = depKeys.length; idx < len; idx++) { + depKey = depKeys[idx]; + // Lookup keys meta for depKey + keys = keysForDep(depsMeta, depKey); + // Decrement the number of times depKey depends on keyName. + keys[keyName] = (keys[keyName] || 0) - 1; + // Unwatch the depKey + unwatch(obj, depKey, meta); + } + } + + __exports__.removeDependentKeys = removeDependentKeys; + }); +enifed("ember-metal/deprecate_property", + ["ember-metal/core","ember-metal/platform","ember-metal/properties","ember-metal/property_get","ember-metal/property_set","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + /** + @module ember-metal + */ + + var Ember = __dependency1__["default"]; + var hasPropertyAccessors = __dependency2__.hasPropertyAccessors; + var defineProperty = __dependency3__.defineProperty; + var get = __dependency4__.get; + var set = __dependency5__.set; + + + /** + Used internally to allow changing properties in a backwards compatible way, and print a helpful + deprecation warning. + + @method deprecateProperty + @param {Object} object The object to add the deprecated property to. + @param {String} deprecatedKey The property to add (and print deprecation warnings upon accessing). + @param {String} newKey The property that will be aliased. + @private + @since 1.7.0 + */ + + function deprecateProperty(object, deprecatedKey, newKey) { + function deprecate() { + } + + if (hasPropertyAccessors) { + defineProperty(object, deprecatedKey, { + configurable: true, + enumerable: false, + set: function(value) { deprecate(); set(this, newKey, value); }, + get: function() { deprecate(); return get(this, newKey); } + }); + } + } + + __exports__.deprecateProperty = deprecateProperty; + }); +enifed("ember-metal/dictionary", + ["ember-metal/platform","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var create = __dependency1__.create; + + // the delete is meant to hint at runtimes that this object should remain in + // dictionary mode. This is clearly a runtime specific hack, but currently it + // appears worthwile in some usecases. Please note, these deletes do increase + // the cost of creation dramatically over a plain Object.create. And as this + // only makes sense for long-lived dictionaries that aren't instantiated often. + __exports__["default"] = function makeDictionary(parent) { + var dict = create(parent); + dict['_dict'] = null; + delete dict['_dict']; + return dict; + } + }); +enifed("ember-metal/enumerable_utils", + ["ember-metal/array","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var _filter = __dependency1__.filter; + var a_forEach = __dependency1__.forEach; + var _indexOf = __dependency1__.indexOf; + var _map = __dependency1__.map; + + var splice = Array.prototype.splice; + + /** + * Defines some convenience methods for working with Enumerables. + * `Ember.EnumerableUtils` uses `Ember.ArrayPolyfills` when necessary. + * + * @class EnumerableUtils + * @namespace Ember + * @static + * */ + + /** + * Calls the map function on the passed object with a specified callback. This + * uses `Ember.ArrayPolyfill`'s-map method when necessary. + * + * @method map + * @param {Object} obj The object that should be mapped + * @param {Function} callback The callback to execute + * @param {Object} thisArg Value to use as this when executing *callback* + * + * @return {Array} An array of mapped values. + */ + function map(obj, callback, thisArg) { + return obj.map ? obj.map(callback, thisArg) : _map.call(obj, callback, thisArg); + } + + __exports__.map = map;/** + * Calls the forEach function on the passed object with a specified callback. This + * uses `Ember.ArrayPolyfill`'s-forEach method when necessary. + * + * @method forEach + * @param {Object} obj The object to call forEach on + * @param {Function} callback The callback to execute + * @param {Object} thisArg Value to use as this when executing *callback* + * + */ + function forEach(obj, callback, thisArg) { + return obj.forEach ? obj.forEach(callback, thisArg) : a_forEach.call(obj, callback, thisArg); + } + + __exports__.forEach = forEach;/** + * Calls the filter function on the passed object with a specified callback. This + * uses `Ember.ArrayPolyfill`'s-filter method when necessary. + * + * @method filter + * @param {Object} obj The object to call filter on + * @param {Function} callback The callback to execute + * @param {Object} thisArg Value to use as this when executing *callback* + * + * @return {Array} An array containing the filtered values + * @since 1.4.0 + */ + function filter(obj, callback, thisArg) { + return obj.filter ? obj.filter(callback, thisArg) : _filter.call(obj, callback, thisArg); + } + + __exports__.filter = filter;/** + * Calls the indexOf function on the passed object with a specified callback. This + * uses `Ember.ArrayPolyfill`'s-indexOf method when necessary. + * + * @method indexOf + * @param {Object} obj The object to call indexOn on + * @param {Function} callback The callback to execute + * @param {Object} index The index to start searching from + * + */ + function indexOf(obj, element, index) { + return obj.indexOf ? obj.indexOf(element, index) : _indexOf.call(obj, element, index); + } + + __exports__.indexOf = indexOf;/** + * Returns an array of indexes of the first occurrences of the passed elements + * on the passed object. + * + * ```javascript + * var array = [1, 2, 3, 4, 5]; + * Ember.EnumerableUtils.indexesOf(array, [2, 5]); // [1, 4] + * + * var fubar = "Fubarr"; + * Ember.EnumerableUtils.indexesOf(fubar, ['b', 'r']); // [2, 4] + * ``` + * + * @method indexesOf + * @param {Object} obj The object to check for element indexes + * @param {Array} elements The elements to search for on *obj* + * + * @return {Array} An array of indexes. + * + */ + function indexesOf(obj, elements) { + return elements === undefined ? [] : map(elements, function(item) { + return indexOf(obj, item); + }); + } + + __exports__.indexesOf = indexesOf;/** + * Adds an object to an array. If the array already includes the object this + * method has no effect. + * + * @method addObject + * @param {Array} array The array the passed item should be added to + * @param {Object} item The item to add to the passed array + * + * @return 'undefined' + */ + function addObject(array, item) { + var index = indexOf(array, item); + if (index === -1) { array.push(item); } + } + + __exports__.addObject = addObject;/** + * Removes an object from an array. If the array does not contain the passed + * object this method has no effect. + * + * @method removeObject + * @param {Array} array The array to remove the item from. + * @param {Object} item The item to remove from the passed array. + * + * @return 'undefined' + */ + function removeObject(array, item) { + var index = indexOf(array, item); + if (index !== -1) { array.splice(index, 1); } + } + + __exports__.removeObject = removeObject;function _replace(array, idx, amt, objects) { + var args = [].concat(objects); + var ret = []; + // https://code.google.com/p/chromium/issues/detail?id=56588 + var size = 60000; + var start = idx; + var ends = amt; + var count, chunk; + + while (args.length) { + count = ends > size ? size : ends; + if (count <= 0) { count = 0; } + + chunk = args.splice(0, size); + chunk = [start, count].concat(chunk); + + start += size; + ends -= count; + + ret = ret.concat(splice.apply(array, chunk)); + } + return ret; + } + + __exports__._replace = _replace;/** + * Replaces objects in an array with the passed objects. + * + * ```javascript + * var array = [1,2,3]; + * Ember.EnumerableUtils.replace(array, 1, 2, [4, 5]); // [1, 4, 5] + * + * var array = [1,2,3]; + * Ember.EnumerableUtils.replace(array, 1, 1, [4, 5]); // [1, 4, 5, 3] + * + * var array = [1,2,3]; + * Ember.EnumerableUtils.replace(array, 10, 1, [4, 5]); // [1, 2, 3, 4, 5] + * ``` + * + * @method replace + * @param {Array} array The array the objects should be inserted into. + * @param {Number} idx Starting index in the array to replace. If *idx* >= + * length, then append to the end of the array. + * @param {Number} amt Number of elements that should be removed from the array, + * starting at *idx* + * @param {Array} objects An array of zero or more objects that should be + * inserted into the array at *idx* + * + * @return {Array} The modified array. + */ + function replace(array, idx, amt, objects) { + if (array.replace) { + return array.replace(idx, amt, objects); + } else { + return _replace(array, idx, amt, objects); + } + } + + __exports__.replace = replace;/** + * Calculates the intersection of two arrays. This method returns a new array + * filled with the records that the two passed arrays share with each other. + * If there is no intersection, an empty array will be returned. + * + * ```javascript + * var array1 = [1, 2, 3, 4, 5]; + * var array2 = [1, 3, 5, 6, 7]; + * + * Ember.EnumerableUtils.intersection(array1, array2); // [1, 3, 5] + * + * var array1 = [1, 2, 3]; + * var array2 = [4, 5, 6]; + * + * Ember.EnumerableUtils.intersection(array1, array2); // [] + * ``` + * + * @method intersection + * @param {Array} array1 The first array + * @param {Array} array2 The second array + * + * @return {Array} The intersection of the two passed arrays. + */ + function intersection(array1, array2) { + var result = []; + forEach(array1, function(element) { + if (indexOf(array2, element) >= 0) { + result.push(element); + } + }); + + return result; + } + + __exports__.intersection = intersection;// TODO: this only exists to maintain the existing api, as we move forward it + // should only be part of the "global build" via some shim + __exports__["default"] = { + _replace: _replace, + addObject: addObject, + filter: filter, + forEach: forEach, + indexOf: indexOf, + indexesOf: indexesOf, + intersection: intersection, + map: map, + removeObject: removeObject, + replace: replace + }; + }); +enifed("ember-metal/error", + ["ember-metal/platform","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var create = __dependency1__.create; + + var errorProps = [ + 'description', + 'fileName', + 'lineNumber', + 'message', + 'name', + 'number', + 'stack' + ]; + + /** + A subclass of the JavaScript Error object for use in Ember. + + @class Error + @namespace Ember + @extends Error + @constructor + */ + function EmberError() { + var tmp = Error.apply(this, arguments); + + // Adds a `stack` property to the given error object that will yield the + // stack trace at the time captureStackTrace was called. + // When collecting the stack trace all frames above the topmost call + // to this function, including that call, will be left out of the + // stack trace. + // This is useful because we can hide Ember implementation details + // that are not very helpful for the user. + if (Error.captureStackTrace) { + Error.captureStackTrace(this, Ember.Error); + } + // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. + for (var idx = 0; idx < errorProps.length; idx++) { + this[errorProps[idx]] = tmp[errorProps[idx]]; + } + } + + EmberError.prototype = create(Error.prototype); + + __exports__["default"] = EmberError; + }); +enifed("ember-metal/events", + ["ember-metal/core","ember-metal/utils","ember-metal/platform","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + /** + @module ember-metal + */ + var Ember = __dependency1__["default"]; + var meta = __dependency2__.meta; + var tryFinally = __dependency2__.tryFinally; + var apply = __dependency2__.apply; + var applyStr = __dependency2__.applyStr; + var create = __dependency3__.create; + + var a_slice = [].slice; + var metaFor = meta; + + /* listener flags */ + var ONCE = 1; + var SUSPENDED = 2; + + + /* + The event system uses a series of nested hashes to store listeners on an + object. When a listener is registered, or when an event arrives, these + hashes are consulted to determine which target and action pair to invoke. + + The hashes are stored in the object's meta hash, and look like this: + + // Object's meta hash + { + listeners: { // variable name: `listenerSet` + "foo:changed": [ // variable name: `actions` + target, method, flags + ] + } + } + + */ + + function indexOf(array, target, method) { + var index = -1; + // hashes are added to the end of the event array + // so it makes sense to start searching at the end + // of the array and search in reverse + for (var i = array.length - 3 ; i >=0; i -= 3) { + if (target === array[i] && method === array[i + 1]) { + index = i; break; + } + } + return index; + } + + function actionsFor(obj, eventName) { + var meta = metaFor(obj, true); + var actions; + + if (!meta.listeners) { meta.listeners = {}; } + + if (!meta.hasOwnProperty('listeners')) { + // setup inherited copy of the listeners object + meta.listeners = create(meta.listeners); + } + + actions = meta.listeners[eventName]; + + // if there are actions, but the eventName doesn't exist in our listeners, then copy them from the prototype + if (actions && !meta.listeners.hasOwnProperty(eventName)) { + actions = meta.listeners[eventName] = meta.listeners[eventName].slice(); + } else if (!actions) { + actions = meta.listeners[eventName] = []; + } + + return actions; + } + + function listenersUnion(obj, eventName, otherActions) { + var meta = obj['__ember_meta__']; + var actions = meta && meta.listeners && meta.listeners[eventName]; + + if (!actions) { return; } + for (var i = actions.length - 3; i >= 0; i -= 3) { + var target = actions[i]; + var method = actions[i+1]; + var flags = actions[i+2]; + var actionIndex = indexOf(otherActions, target, method); + + if (actionIndex === -1) { + otherActions.push(target, method, flags); + } + } + } + + __exports__.listenersUnion = listenersUnion;function listenersDiff(obj, eventName, otherActions) { + var meta = obj['__ember_meta__']; + var actions = meta && meta.listeners && meta.listeners[eventName]; + var diffActions = []; + + if (!actions) { return; } + for (var i = actions.length - 3; i >= 0; i -= 3) { + var target = actions[i]; + var method = actions[i+1]; + var flags = actions[i+2]; + var actionIndex = indexOf(otherActions, target, method); + + if (actionIndex !== -1) { continue; } + + otherActions.push(target, method, flags); + diffActions.push(target, method, flags); + } + + return diffActions; + } + + __exports__.listenersDiff = listenersDiff;/** + Add an event listener + + @method addListener + @for Ember + @param obj + @param {String} eventName + @param {Object|Function} targetOrMethod A target object or a function + @param {Function|String} method A function or the name of a function to be called on `target` + @param {Boolean} once A flag whether a function should only be called once + */ + function addListener(obj, eventName, target, method, once) { + + if (!method && 'function' === typeof target) { + method = target; + target = null; + } + + var actions = actionsFor(obj, eventName); + var actionIndex = indexOf(actions, target, method); + var flags = 0; + + if (once) flags |= ONCE; + + if (actionIndex !== -1) { return; } + + actions.push(target, method, flags); + + if ('function' === typeof obj.didAddListener) { + obj.didAddListener(eventName, target, method); + } + } + + __exports__.addListener = addListener;/** + Remove an event listener + + Arguments should match those passed to `Ember.addListener`. + + @method removeListener + @for Ember + @param obj + @param {String} eventName + @param {Object|Function} targetOrMethod A target object or a function + @param {Function|String} method A function or the name of a function to be called on `target` + */ + function removeListener(obj, eventName, target, method) { + + if (!method && 'function' === typeof target) { + method = target; + target = null; + } + + function _removeListener(target, method) { + var actions = actionsFor(obj, eventName); + var actionIndex = indexOf(actions, target, method); + + // action doesn't exist, give up silently + if (actionIndex === -1) { return; } + + actions.splice(actionIndex, 3); + + if ('function' === typeof obj.didRemoveListener) { + obj.didRemoveListener(eventName, target, method); + } + } + + if (method) { + _removeListener(target, method); + } else { + var meta = obj['__ember_meta__']; + var actions = meta && meta.listeners && meta.listeners[eventName]; + + if (!actions) { return; } + for (var i = actions.length - 3; i >= 0; i -= 3) { + _removeListener(actions[i], actions[i+1]); + } + } + } + + /** + Suspend listener during callback. + + This should only be used by the target of the event listener + when it is taking an action that would cause the event, e.g. + an object might suspend its property change listener while it is + setting that property. + + @method suspendListener + @for Ember + + @private + @param obj + @param {String} eventName + @param {Object|Function} targetOrMethod A target object or a function + @param {Function|String} method A function or the name of a function to be called on `target` + @param {Function} callback + */ + function suspendListener(obj, eventName, target, method, callback) { + if (!method && 'function' === typeof target) { + method = target; + target = null; + } + + var actions = actionsFor(obj, eventName); + var actionIndex = indexOf(actions, target, method); + + if (actionIndex !== -1) { + actions[actionIndex+2] |= SUSPENDED; // mark the action as suspended + } + + function tryable() { return callback.call(target); } + function finalizer() { if (actionIndex !== -1) { actions[actionIndex+2] &= ~SUSPENDED; } } + + return tryFinally(tryable, finalizer); + } + + __exports__.suspendListener = suspendListener;/** + Suspends multiple listeners during a callback. + + @method suspendListeners + @for Ember + + @private + @param obj + @param {Array} eventName Array of event names + @param {Object|Function} targetOrMethod A target object or a function + @param {Function|String} method A function or the name of a function to be called on `target` + @param {Function} callback + */ + function suspendListeners(obj, eventNames, target, method, callback) { + if (!method && 'function' === typeof target) { + method = target; + target = null; + } + + var suspendedActions = []; + var actionsList = []; + var eventName, actions, i, l; + + for (i=0, l=eventNames.length; i= 0; i -= 3) { // looping in reverse for once listeners + var target = actions[i], method = actions[i+1], flags = actions[i+2]; + if (!method) { continue; } + if (flags & SUSPENDED) { continue; } + if (flags & ONCE) { removeListener(obj, eventName, target, method); } + if (!target) { target = obj; } + if ('string' === typeof method) { + if (params) { + applyStr(target, method, params); + } else { + target[method](); + } + } else { + if (params) { + apply(target, method, params); + } else { + method.call(target); + } + } + } + return true; + } + + __exports__.sendEvent = sendEvent;/** + @private + @method hasListeners + @for Ember + @param obj + @param {String} eventName + */ + function hasListeners(obj, eventName) { + var meta = obj['__ember_meta__']; + var actions = meta && meta.listeners && meta.listeners[eventName]; + + return !!(actions && actions.length); + } + + __exports__.hasListeners = hasListeners;/** + @private + @method listenersFor + @for Ember + @param obj + @param {String} eventName + */ + function listenersFor(obj, eventName) { + var ret = []; + var meta = obj['__ember_meta__']; + var actions = meta && meta.listeners && meta.listeners[eventName]; + + if (!actions) { return ret; } + + for (var i = 0, l = actions.length; i < l; i += 3) { + var target = actions[i]; + var method = actions[i+1]; + ret.push([target, method]); + } + + return ret; + } + + __exports__.listenersFor = listenersFor;/** + Define a property as a function that should be executed when + a specified event or events are triggered. + + + ``` javascript + var Job = Ember.Object.extend({ + logCompleted: Ember.on('completed', function() { + console.log('Job completed!'); + }) + }); + + var job = Job.create(); + + Ember.sendEvent(job, 'completed'); // Logs 'Job completed!' + ``` + + @method on + @for Ember + @param {String} eventNames* + @param {Function} func + @return func + */ + function on(){ + var func = a_slice.call(arguments, -1)[0]; + var events = a_slice.call(arguments, 0, -1); + func.__ember_listens__ = events; + return func; + } + + __exports__.on = on;__exports__.removeListener = removeListener; + }); +enifed("ember-metal/expand_properties", + ["ember-metal/core","ember-metal/error","ember-metal/enumerable_utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var EmberError = __dependency2__["default"]; + var forEach = __dependency3__.forEach; + + /** + @module ember-metal + */ + + var BRACE_EXPANSION = /^((?:[^\.]*\.)*)\{(.*)\}$/; + var SPLIT_REGEX = /\{|\}/; + + /** + Expands `pattern`, invoking `callback` for each expansion. + + The only pattern supported is brace-expansion, anything else will be passed + once to `callback` directly. + + Example + + ```js + function echo(arg){ console.log(arg); } + + Ember.expandProperties('foo.bar', echo); //=> 'foo.bar' + Ember.expandProperties('{foo,bar}', echo); //=> 'foo', 'bar' + Ember.expandProperties('foo.{bar,baz}', echo); //=> 'foo.bar', 'foo.baz' + Ember.expandProperties('{foo,bar}.baz', echo); //=> '{foo,bar}.baz' + Ember.expandProperties('foo.{bar,baz}.@each', echo) //=> 'foo.bar.@each', 'foo.baz.@each' + Ember.expandProperties('{foo,bar}.{spam,eggs}', echo) //=> 'foo.spam', 'foo.eggs', 'bar.spam', 'bar.eggs' + Ember.expandProperties('{foo}.bar.{baz}') //=> 'foo.bar.baz' + ``` + + @method + @private + @param {String} pattern The property pattern to expand. + @param {Function} callback The callback to invoke. It is invoked once per + expansion, and is passed the expansion. + */ + __exports__["default"] = function expandProperties(pattern, callback) { + if (pattern.indexOf(' ') > -1) { + throw new EmberError('Brace expanded properties cannot contain spaces, ' + + 'e.g. `user.{firstName, lastName}` should be `user.{firstName,lastName}`'); + } + + + return newExpandProperties(pattern, callback); + } + + function oldExpandProperties(pattern, callback) { + var match, prefix, list; + + if (match = BRACE_EXPANSION.exec(pattern)) { + prefix = match[1]; + list = match[2]; + + forEach(list.split(','), function (suffix) { + callback(prefix + suffix); + }); + } else { + callback(pattern); + } + } + + function newExpandProperties(pattern, callback) { + if ('string' === Ember.typeOf(pattern)) { + var parts = pattern.split(SPLIT_REGEX); + var properties = [parts]; + + forEach(parts, function(part, index) { + if (part.indexOf(',') >= 0) { + properties = duplicateAndReplace(properties, part.split(','), index); + } + }); + + forEach(properties, function(property) { + callback(property.join('')); + }); + } else { + callback(pattern); + } + } + + function duplicateAndReplace(properties, currentParts, index) { + var all = []; + + forEach(properties, function(property) { + forEach(currentParts, function(part) { + var current = property.slice(0); + current[index] = part; + all.push(current); + }); + }); + + return all; + } + }); +enifed("ember-metal/get_properties", + ["ember-metal/property_get","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var typeOf = __dependency2__.typeOf; + + /** + To get multiple properties at once, call `Ember.getProperties` + with an object followed by a list of strings or an array: + + ```javascript + Ember.getProperties(record, 'firstName', 'lastName', 'zipCode'); + // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } + ``` + + is equivalent to: + + ```javascript + Ember.getProperties(record, ['firstName', 'lastName', 'zipCode']); + // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } + ``` + + @method getProperties + @param obj + @param {String...|Array} list of keys to get + @return {Hash} + */ + __exports__["default"] = function getProperties(obj) { + var ret = {}; + var propertyNames = arguments; + var i = 1; + + if (arguments.length === 2 && typeOf(arguments[1]) === 'array') { + i = 0; + propertyNames = arguments[1]; + } + for(var len = propertyNames.length; i < len; i++) { + ret[propertyNames[i]] = get(obj, propertyNames[i]); + } + return ret; + } + }); +enifed("ember-metal/instrumentation", + ["ember-metal/core","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var tryCatchFinally = __dependency2__.tryCatchFinally; + + /** + The purpose of the Ember Instrumentation module is + to provide efficient, general-purpose instrumentation + for Ember. + + Subscribe to a listener by using `Ember.subscribe`: + + ```javascript + Ember.subscribe("render", { + before: function(name, timestamp, payload) { + + }, + + after: function(name, timestamp, payload) { + + } + }); + ``` + + If you return a value from the `before` callback, that same + value will be passed as a fourth parameter to the `after` + callback. + + Instrument a block of code by using `Ember.instrument`: + + ```javascript + Ember.instrument("render.handlebars", payload, function() { + // rendering logic + }, binding); + ``` + + Event names passed to `Ember.instrument` are namespaced + by periods, from more general to more specific. Subscribers + can listen for events by whatever level of granularity they + are interested in. + + In the above example, the event is `render.handlebars`, + and the subscriber listened for all events beginning with + `render`. It would receive callbacks for events named + `render`, `render.handlebars`, `render.container`, or + even `render.handlebars.layout`. + + @class Instrumentation + @namespace Ember + @static + */ + var subscribers = []; + __exports__.subscribers = subscribers;var cache = {}; + + var populateListeners = function(name) { + var listeners = []; + var subscriber; + + for (var i=0, l=subscribers.length; i -1) { + list.splice(index, 1); + } + this.size = list.length; + return true; + } else { + return false; + } + }, + + /** + @method isEmpty + @return {Boolean} + */ + isEmpty: function() { + return this.size === 0; + }, + + /** + @method has + @param obj + @return {Boolean} + */ + has: function(obj) { + if (this.size === 0) { return false; } + + var guid = guidFor(obj); + var presenceSet = this.presenceSet; + + return presenceSet[guid] === true; + }, + + /** + @method forEach + @param {Function} fn + @param self + */ + forEach: function(fn /*, thisArg*/) { + if (typeof fn !== 'function') { + missingFunction(fn); + } + + if (this.size === 0) { return; } + + var list = this.list; + var length = arguments.length; + var i; + + if (length === 2) { + for (i = 0; i < list.length; i++) { + fn.call(arguments[1], list[i]); + } + } else { + for (i = 0; i < list.length; i++) { + fn(list[i]); + } + } + }, + + /** + @method toArray + @return {Array} + */ + toArray: function() { + return this.list.slice(); + }, + + /** + @method copy + @return {Ember.OrderedSet} + */ + copy: function() { + var Constructor = this.constructor; + var set = new Constructor(); + + set._silenceRemoveDeprecation = this._silenceRemoveDeprecation; + set.presenceSet = copyNull(this.presenceSet); + set.list = this.toArray(); + set.size = this.size; + + return set; + } + }; + + deprecateProperty(OrderedSet.prototype, 'length', 'size'); + + /** + A Map stores values indexed by keys. Unlike JavaScript's + default Objects, the keys of a Map can be any JavaScript + object. + + Internally, a Map has two data structures: + + 1. `keys`: an OrderedSet of all of the existing keys + 2. `values`: a JavaScript Object indexed by the `Ember.guidFor(key)` + + When a key/value pair is added for the first time, we + add the key to the `keys` OrderedSet, and create or + replace an entry in `values`. When an entry is deleted, + we delete its entry in `keys` and `values`. + + @class Map + @namespace Ember + @private + @constructor + */ + function Map() { + if (this instanceof this.constructor) { + this.keys = OrderedSet.create(); + this.keys._silenceRemoveDeprecation = true; + this.values = create(null); + this.size = 0; + } else { + missingNew("OrderedSet"); + } + } + + Ember.Map = Map; + + /** + @method create + @static + */ + Map.create = function() { + var Constructor = this; + return new Constructor(); + }; + + Map.prototype = { + constructor: Map, + + /** + This property will change as the number of objects in the map changes. + + @property size + @type number + @default 0 + */ + size: 0, + + /** + Retrieve the value associated with a given key. + + @method get + @param {*} key + @return {*} the value associated with the key, or `undefined` + */ + get: function(key) { + if (this.size === 0) { return; } + + var values = this.values; + var guid = guidFor(key); + + return values[guid]; + }, + + /** + Adds a value to the map. If a value for the given key has already been + provided, the new value will replace the old value. + + @method set + @param {*} key + @param {*} value + @return {Ember.Map} + */ + set: function(key, value) { + var keys = this.keys; + var values = this.values; + var guid = guidFor(key); + + // ensure we don't store -0 + var k = key === -0 ? 0 : key; + + keys.add(k, guid); + + values[guid] = value; + + this.size = keys.size; + + return this; + }, + + /** + @deprecated see delete + Removes a value from the map for an associated key. + + @method remove + @param {*} key + @return {Boolean} true if an item was removed, false otherwise + */ + remove: function(key) { + + return this["delete"](key); + }, + + /** + Removes a value from the map for an associated key. + + @method delete + @param {*} key + @return {Boolean} true if an item was removed, false otherwise + */ + "delete": function(key) { + if (this.size === 0) { return false; } + // don't use ES6 "delete" because it will be annoying + // to use in browsers that are not ES6 friendly; + var keys = this.keys; + var values = this.values; + var guid = guidFor(key); + + if (keys["delete"](key, guid)) { + delete values[guid]; + this.size = keys.size; + return true; + } else { + return false; + } + }, + + /** + Check whether a key is present. + + @method has + @param {*} key + @return {Boolean} true if the item was present, false otherwise + */ + has: function(key) { + return this.keys.has(key); + }, + + /** + Iterate over all the keys and values. Calls the function once + for each key, passing in the key and value, in that order. + + The keys are guaranteed to be iterated over in insertion order. + + @method forEach + @param {Function} callback + @param {*} self if passed, the `this` value inside the + callback. By default, `this` is the map. + */ + forEach: function(callback /*, thisArg*/) { + if (typeof callback !== 'function') { + missingFunction(callback); + } + + if (this.size === 0) { return; } + + var length = arguments.length; + var map = this; + var cb, thisArg; + + if (length === 2) { + thisArg = arguments[1]; + cb = function(key) { + callback.call(thisArg, map.get(key), key); + }; + } else { + cb = function(key) { + callback(map.get(key), key); + }; + } + + this.keys.forEach(cb); + }, + + /** + @method clear + */ + clear: function() { + this.keys.clear(); + this.values = create(null); + this.size = 0; + }, + + /** + @method copy + @return {Ember.Map} + */ + copy: function() { + return copyMap(this, new Map()); + } + }; + + deprecateProperty(Map.prototype, 'length', 'size'); + + /** + @class MapWithDefault + @namespace Ember + @extends Ember.Map + @private + @constructor + @param [options] + @param {*} [options.defaultValue] + */ + function MapWithDefault(options) { + this._super$constructor(); + this.defaultValue = options.defaultValue; + } + + /** + @method create + @static + @param [options] + @param {*} [options.defaultValue] + @return {Ember.MapWithDefault|Ember.Map} If options are passed, returns + `Ember.MapWithDefault` otherwise returns `Ember.Map` + */ + MapWithDefault.create = function(options) { + if (options) { + return new MapWithDefault(options); + } else { + return new Map(); + } + }; + + MapWithDefault.prototype = create(Map.prototype); + MapWithDefault.prototype.constructor = MapWithDefault; + MapWithDefault.prototype._super$constructor = Map; + MapWithDefault.prototype._super$get = Map.prototype.get; + + /** + Retrieve the value associated with a given key. + + @method get + @param {*} key + @return {*} the value associated with the key, or the default value + */ + MapWithDefault.prototype.get = function(key) { + var hasValue = this.has(key); + + if (hasValue) { + return this._super$get(key); + } else { + var defaultValue = this.defaultValue(key); + this.set(key, defaultValue); + return defaultValue; + } + }; + + /** + @method copy + @return {Ember.MapWithDefault} + */ + MapWithDefault.prototype.copy = function() { + var Constructor = this.constructor; + return copyMap(this, new Constructor({ + defaultValue: this.defaultValue + })); + }; + + __exports__["default"] = Map; + + __exports__.OrderedSet = OrderedSet; + __exports__.Map = Map; + __exports__.MapWithDefault = MapWithDefault; + }); +enifed("ember-metal/merge", + ["ember-metal/keys","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var keys = __dependency1__["default"]; + + /** + Merge the contents of two objects together into the first object. + + ```javascript + Ember.merge({first: 'Tom'}, {last: 'Dale'}); // {first: 'Tom', last: 'Dale'} + var a = {first: 'Yehuda'}, b = {last: 'Katz'}; + Ember.merge(a, b); // a == {first: 'Yehuda', last: 'Katz'}, b == {last: 'Katz'} + ``` + + @method merge + @for Ember + @param {Object} original The object to merge into + @param {Object} updates The object to copy properties from + @return {Object} + */ + __exports__["default"] = function merge(original, updates) { + if (!updates || typeof updates !== 'object') { + return original; + } + + var props = keys(updates); + var prop; + var length = props.length; + + for (var i = 0; i < length; i++) { + prop = props[i]; + original[prop] = updates[prop]; + } + + return original; + } + }); +enifed("ember-metal/mixin", + ["ember-metal/core","ember-metal/merge","ember-metal/array","ember-metal/platform","ember-metal/utils","ember-metal/expand_properties","ember-metal/properties","ember-metal/computed","ember-metal/binding","ember-metal/observer","ember-metal/events","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-metal + */ + + var Ember = __dependency1__["default"]; + // warn, assert, wrap, et; + var merge = __dependency2__["default"]; + var map = __dependency3__.map; + var indexOf = __dependency3__.indexOf; + var forEach = __dependency3__.forEach; + var create = __dependency4__.create; + var guidFor = __dependency5__.guidFor; + var meta = __dependency5__.meta; + var wrap = __dependency5__.wrap; + var makeArray = __dependency5__.makeArray; + var apply = __dependency5__.apply; + var isArray = __dependency5__.isArray; + var expandProperties = __dependency6__["default"]; + var Descriptor = __dependency7__.Descriptor; + var defineProperty = __dependency7__.defineProperty; + var ComputedProperty = __dependency8__.ComputedProperty; + var Binding = __dependency9__.Binding; + var addObserver = __dependency10__.addObserver; + var removeObserver = __dependency10__.removeObserver; + var addBeforeObserver = __dependency10__.addBeforeObserver; + var removeBeforeObserver = __dependency10__.removeBeforeObserver; + var addListener = __dependency11__.addListener; + var removeListener = __dependency11__.removeListener; + + var REQUIRED; + var a_map = map; + var a_indexOf = indexOf; + var a_forEach = forEach; + var a_slice = [].slice; + var o_create = create; + var metaFor = meta; + + function superFunction(){ + var func = this.__nextSuper; + var ret; + if (func) { + var args = new Array(arguments.length); + for (var i = 0, l = args.length; i < l; i++) { + args[i] = arguments[i]; + } + this.__nextSuper = null; + ret = apply(this, func, args); + this.__nextSuper = func; + } + return ret; + } + + function mixinsMeta(obj) { + var m = metaFor(obj, true); + var ret = m.mixins; + if (!ret) { + ret = m.mixins = {}; + } else if (!m.hasOwnProperty('mixins')) { + ret = m.mixins = o_create(ret); + } + return ret; + } + + function initMixin(mixin, args) { + if (args && args.length > 0) { + mixin.mixins = a_map.call(args, function(x) { + if (x instanceof Mixin) { return x; } + + // Note: Manually setup a primitive mixin here. This is the only + // way to actually get a primitive mixin. This way normal creation + // of mixins will give you combined mixins... + var mixin = new Mixin(); + mixin.properties = x; + return mixin; + }); + } + return mixin; + } + + function isMethod(obj) { + return 'function' === typeof obj && + obj.isMethod !== false && + obj !== Boolean && obj !== Object && obj !== Number && obj !== Array && obj !== Date && obj !== String; + } + + var CONTINUE = {}; + + function mixinProperties(mixinsMeta, mixin) { + var guid; + + if (mixin instanceof Mixin) { + guid = guidFor(mixin); + if (mixinsMeta[guid]) { return CONTINUE; } + mixinsMeta[guid] = mixin; + return mixin.properties; + } else { + return mixin; // apply anonymous mixin properties + } + } + + function concatenatedMixinProperties(concatProp, props, values, base) { + var concats; + + // reset before adding each new mixin to pickup concats from previous + concats = values[concatProp] || base[concatProp]; + if (props[concatProp]) { + concats = concats ? concats.concat(props[concatProp]) : props[concatProp]; + } + + return concats; + } + + function giveDescriptorSuper(meta, key, property, values, descs) { + var superProperty; + + // Computed properties override methods, and do not call super to them + if (values[key] === undefined) { + // Find the original descriptor in a parent mixin + superProperty = descs[key]; + } + + // If we didn't find the original descriptor in a parent mixin, find + // it on the original object. + superProperty = superProperty || meta.descs[key]; + + if (superProperty === undefined || !(superProperty instanceof ComputedProperty)) { + return property; + } + + // Since multiple mixins may inherit from the same parent, we need + // to clone the computed property so that other mixins do not receive + // the wrapped version. + property = o_create(property); + property.func = wrap(property.func, superProperty.func); + + return property; + } + + function giveMethodSuper(obj, key, method, values, descs) { + var superMethod; + + // Methods overwrite computed properties, and do not call super to them. + if (descs[key] === undefined) { + // Find the original method in a parent mixin + superMethod = values[key]; + } + + // If we didn't find the original value in a parent mixin, find it in + // the original object + superMethod = superMethod || obj[key]; + + // Only wrap the new method if the original method was a function + if (superMethod === undefined || 'function' !== typeof superMethod) { + return method; + } + + return wrap(method, superMethod); + } + + function applyConcatenatedProperties(obj, key, value, values) { + var baseValue = values[key] || obj[key]; + + if (baseValue) { + if ('function' === typeof baseValue.concat) { + return baseValue.concat(value); + } else { + return makeArray(baseValue).concat(value); + } + } else { + return makeArray(value); + } + } + + function applyMergedProperties(obj, key, value, values) { + var baseValue = values[key] || obj[key]; + + + if (!baseValue) { return value; } + + var newBase = merge({}, baseValue); + var hasFunction = false; + + for (var prop in value) { + if (!value.hasOwnProperty(prop)) { continue; } + + var propValue = value[prop]; + if (isMethod(propValue)) { + // TODO: support for Computed Properties, etc? + hasFunction = true; + newBase[prop] = giveMethodSuper(obj, prop, propValue, baseValue, {}); + } else { + newBase[prop] = propValue; + } + } + + if (hasFunction) { + newBase._super = superFunction; + } + + return newBase; + } + + function addNormalizedProperty(base, key, value, meta, descs, values, concats, mergings) { + if (value instanceof Descriptor) { + if (value === REQUIRED && descs[key]) { return CONTINUE; } + + // Wrap descriptor function to implement + // __nextSuper() if needed + if (value.func) { + value = giveDescriptorSuper(meta, key, value, values, descs); + } + + descs[key] = value; + values[key] = undefined; + } else { + if ((concats && a_indexOf.call(concats, key) >= 0) || + key === 'concatenatedProperties' || + key === 'mergedProperties') { + value = applyConcatenatedProperties(base, key, value, values); + } else if ((mergings && a_indexOf.call(mergings, key) >= 0)) { + value = applyMergedProperties(base, key, value, values); + } else if (isMethod(value)) { + value = giveMethodSuper(base, key, value, values, descs); + } + + descs[key] = undefined; + values[key] = value; + } + } + + function mergeMixins(mixins, m, descs, values, base, keys) { + var mixin, props, key, concats, mergings, meta; + + function removeKeys(keyName) { + delete descs[keyName]; + delete values[keyName]; + } + + for(var i=0, l=mixins.length; i= 0) { + if (_detect(mixins[loc], targetMixin, seen)) { return true; } + } + return false; + } + + /** + @method detect + @param obj + @return {Boolean} + */ + MixinPrototype.detect = function(obj) { + if (!obj) { return false; } + if (obj instanceof Mixin) { return _detect(obj, this, {}); } + var m = obj['__ember_meta__']; + var mixins = m && m.mixins; + if (mixins) { + return !!mixins[guidFor(this)]; + } + return false; + }; + + MixinPrototype.without = function() { + var ret = new Mixin(this); + ret._without = a_slice.call(arguments); + return ret; + }; + + function _keys(ret, mixin, seen) { + if (seen[guidFor(mixin)]) { return; } + seen[guidFor(mixin)] = true; + + if (mixin.properties) { + var props = mixin.properties; + for (var key in props) { + if (props.hasOwnProperty(key)) { ret[key] = true; } + } + } else if (mixin.mixins) { + a_forEach.call(mixin.mixins, function(x) { _keys(ret, x, seen); }); + } + } + + MixinPrototype.keys = function() { + var keys = {}; + var seen = {}; + var ret = []; + _keys(keys, this, seen); + for(var key in keys) { + if (keys.hasOwnProperty(key)) { ret.push(key); } + } + return ret; + }; + + // returns the mixins currently applied to the specified object + // TODO: Make Ember.mixin + Mixin.mixins = function(obj) { + var m = obj['__ember_meta__']; + var mixins = m && m.mixins; + var ret = []; + + if (!mixins) { return ret; } + + for (var key in mixins) { + var mixin = mixins[key]; + + // skip primitive mixins since these are always anonymous + if (!mixin.properties) { ret.push(mixin); } + } + + return ret; + }; + + REQUIRED = new Descriptor(); + REQUIRED.toString = function() { return '(Required Property)'; }; + + /** + Denotes a required property for a mixin + + @method required + @for Ember + */ + function required() { + return REQUIRED; + } + + __exports__.required = required;function Alias(methodName) { + this.methodName = methodName; + } + + Alias.prototype = new Descriptor(); + + /** + Makes a method available via an additional name. + + ```javascript + App.Person = Ember.Object.extend({ + name: function() { + return 'Tomhuda Katzdale'; + }, + moniker: Ember.aliasMethod('name') + }); + + var goodGuy = App.Person.create(); + + goodGuy.name(); // 'Tomhuda Katzdale' + goodGuy.moniker(); // 'Tomhuda Katzdale' + ``` + + @method aliasMethod + @for Ember + @param {String} methodName name of the method to alias + @return {Ember.Descriptor} + */ + function aliasMethod(methodName) { + return new Alias(methodName); + } + + __exports__.aliasMethod = aliasMethod;// .......................................................... + // OBSERVER HELPER + // + + /** + Specify a method that observes property changes. + + ```javascript + Ember.Object.extend({ + valueObserver: Ember.observer('value', function() { + // Executes whenever the "value" property changes + }) + }); + ``` + + In the future this method may become asynchronous. If you want to ensure + synchronous behavior, use `immediateObserver`. + + Also available as `Function.prototype.observes` if prototype extensions are + enabled. + + @method observer + @for Ember + @param {String} propertyNames* + @param {Function} func + @return func + */ + function observer() { + var func = a_slice.call(arguments, -1)[0]; + var paths; + + var addWatchedProperty = function (path) { paths.push(path); }; + var _paths = a_slice.call(arguments, 0, -1); + + if (typeof func !== "function") { + // revert to old, soft-deprecated argument ordering + + func = arguments[0]; + _paths = a_slice.call(arguments, 1); + } + + paths = []; + + for (var i=0; i<_paths.length; ++i) { + expandProperties(_paths[i], addWatchedProperty); + } + + if (typeof func !== "function") { + throw new Ember.Error("Ember.observer called without a function"); + } + + func.__ember_observes__ = paths; + return func; + } + + __exports__.observer = observer;/** + Specify a method that observes property changes. + + ```javascript + Ember.Object.extend({ + valueObserver: Ember.immediateObserver('value', function() { + // Executes whenever the "value" property changes + }) + }); + ``` + + In the future, `Ember.observer` may become asynchronous. In this event, + `Ember.immediateObserver` will maintain the synchronous behavior. + + Also available as `Function.prototype.observesImmediately` if prototype extensions are + enabled. + + @method immediateObserver + @for Ember + @param {String} propertyNames* + @param {Function} func + @return func + */ + function immediateObserver() { + for (var i=0, l=arguments.length; i this.changingFrom ? 'green' : 'red'; + // logic + } + }), + + friendsDidChange: Ember.observer('friends.@each.name', function(obj, keyName) { + // some logic + // obj.get(keyName) returns friends array + }) + }); + ``` + + Also available as `Function.prototype.observesBefore` if prototype extensions are + enabled. + + @method beforeObserver + @for Ember + @param {String} propertyNames* + @param {Function} func + @return func + */ + function beforeObserver() { + var func = a_slice.call(arguments, -1)[0]; + var paths; + + var addWatchedProperty = function(path) { paths.push(path); }; + + var _paths = a_slice.call(arguments, 0, -1); + + if (typeof func !== "function") { + // revert to old, soft-deprecated argument ordering + + func = arguments[0]; + _paths = a_slice.call(arguments, 1); + } + + paths = []; + + for (var i=0; i<_paths.length; ++i) { + expandProperties(_paths[i], addWatchedProperty); + } + + if (typeof func !== "function") { + throw new Ember.Error("Ember.beforeObserver called without a function"); + } + + func.__ember_observesBefore__ = paths; + return func; + } + + __exports__.beforeObserver = beforeObserver;__exports__.IS_BINDING = IS_BINDING; + __exports__.Mixin = Mixin; + }); +enifed("ember-metal/observer", + ["ember-metal/watching","ember-metal/array","ember-metal/events","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var watch = __dependency1__.watch; + var unwatch = __dependency1__.unwatch; + var map = __dependency2__.map; + var listenersFor = __dependency3__.listenersFor; + var addListener = __dependency3__.addListener; + var removeListener = __dependency3__.removeListener; + var suspendListeners = __dependency3__.suspendListeners; + var suspendListener = __dependency3__.suspendListener; + /** + @module ember-metal + */ + + var AFTER_OBSERVERS = ':change'; + var BEFORE_OBSERVERS = ':before'; + + function changeEvent(keyName) { + return keyName + AFTER_OBSERVERS; + } + + function beforeEvent(keyName) { + return keyName + BEFORE_OBSERVERS; + } + + /** + @method addObserver + @for Ember + @param obj + @param {String} path + @param {Object|Function} targetOrMethod + @param {Function|String} [method] + */ + function addObserver(obj, _path, target, method) { + addListener(obj, changeEvent(_path), target, method); + watch(obj, _path); + + return this; + } + + __exports__.addObserver = addObserver;function observersFor(obj, path) { + return listenersFor(obj, changeEvent(path)); + } + + __exports__.observersFor = observersFor;/** + @method removeObserver + @for Ember + @param obj + @param {String} path + @param {Object|Function} targetOrMethod + @param {Function|String} [method] + */ + function removeObserver(obj, _path, target, method) { + unwatch(obj, _path); + removeListener(obj, changeEvent(_path), target, method); + + return this; + } + + __exports__.removeObserver = removeObserver;/** + @method addBeforeObserver + @for Ember + @param obj + @param {String} path + @param {Object|Function} targetOrMethod + @param {Function|String} [method] + */ + function addBeforeObserver(obj, _path, target, method) { + addListener(obj, beforeEvent(_path), target, method); + watch(obj, _path); + + return this; + } + + __exports__.addBeforeObserver = addBeforeObserver;// Suspend observer during callback. + // + // This should only be used by the target of the observer + // while it is setting the observed path. + function _suspendBeforeObserver(obj, path, target, method, callback) { + return suspendListener(obj, beforeEvent(path), target, method, callback); + } + + __exports__._suspendBeforeObserver = _suspendBeforeObserver;function _suspendObserver(obj, path, target, method, callback) { + return suspendListener(obj, changeEvent(path), target, method, callback); + } + + __exports__._suspendObserver = _suspendObserver;function _suspendBeforeObservers(obj, paths, target, method, callback) { + var events = map.call(paths, beforeEvent); + return suspendListeners(obj, events, target, method, callback); + } + + __exports__._suspendBeforeObservers = _suspendBeforeObservers;function _suspendObservers(obj, paths, target, method, callback) { + var events = map.call(paths, changeEvent); + return suspendListeners(obj, events, target, method, callback); + } + + __exports__._suspendObservers = _suspendObservers;function beforeObserversFor(obj, path) { + return listenersFor(obj, beforeEvent(path)); + } + + __exports__.beforeObserversFor = beforeObserversFor;/** + @method removeBeforeObserver + @for Ember + @param obj + @param {String} path + @param {Object|Function} targetOrMethod + @param {Function|String} [method] + */ + function removeBeforeObserver(obj, _path, target, method) { + unwatch(obj, _path); + removeListener(obj, beforeEvent(_path), target, method); + + return this; + } + + __exports__.removeBeforeObserver = removeBeforeObserver; + }); +enifed("ember-metal/observer_set", + ["ember-metal/utils","ember-metal/events","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var guidFor = __dependency1__.guidFor; + var sendEvent = __dependency2__.sendEvent; + + /* + this.observerSet = { + [senderGuid]: { // variable name: `keySet` + [keyName]: listIndex + } + }, + this.observers = [ + { + sender: obj, + keyName: keyName, + eventName: eventName, + listeners: [ + [target, method, flags] + ] + }, + ... + ] + */ + __exports__["default"] = ObserverSet; + function ObserverSet() { + this.clear(); + } + + + ObserverSet.prototype.add = function(sender, keyName, eventName) { + var observerSet = this.observerSet; + var observers = this.observers; + var senderGuid = guidFor(sender); + var keySet = observerSet[senderGuid]; + var index; + + if (!keySet) { + observerSet[senderGuid] = keySet = {}; + } + index = keySet[keyName]; + if (index === undefined) { + index = observers.push({ + sender: sender, + keyName: keyName, + eventName: eventName, + listeners: [] + }) - 1; + keySet[keyName] = index; + } + return observers[index].listeners; + }; + + ObserverSet.prototype.flush = function() { + var observers = this.observers; + var i, len, observer, sender; + this.clear(); + for (i=0, len=observers.length; i < len; ++i) { + observer = observers[i]; + sender = observer.sender; + if (sender.isDestroying || sender.isDestroyed) { continue; } + sendEvent(sender, observer.eventName, [sender, observer.keyName], observer.listeners); + } + }; + + ObserverSet.prototype.clear = function() { + this.observerSet = {}; + this.observers = []; + }; + }); +enifed("ember-metal/path_cache", + ["ember-metal/cache","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Cache = __dependency1__["default"]; + + var IS_GLOBAL = /^([A-Z$]|([0-9][A-Z$]))/; + var IS_GLOBAL_PATH = /^([A-Z$]|([0-9][A-Z$])).*[\.]/; + var HAS_THIS = 'this.'; + + var isGlobalCache = new Cache(1000, function(key) { return IS_GLOBAL.test(key); }); + var isGlobalPathCache = new Cache(1000, function(key) { return IS_GLOBAL_PATH.test(key); }); + var hasThisCache = new Cache(1000, function(key) { return key.indexOf(HAS_THIS) !== -1; }); + var isPathCache = new Cache(1000, function(key) { return key.indexOf('.') !== -1; }); + + var caches = { + isGlobalCache: isGlobalCache, + isGlobalPathCache: isGlobalPathCache, + hasThisCache: hasThisCache, + isPathCache: isPathCache + }; + __exports__.caches = caches; + function isGlobal(path) { + return isGlobalCache.get(path); + } + + __exports__.isGlobal = isGlobal;function isGlobalPath(path) { + return isGlobalPathCache.get(path); + } + + __exports__.isGlobalPath = isGlobalPath;function hasThis(path) { + return hasThisCache.get(path); + } + + __exports__.hasThis = hasThis;function isPath(path) { + return isPathCache.get(path); + } + + __exports__.isPath = isPath; + }); +enifed("ember-metal/platform", + ["ember-metal/platform/define_property","ember-metal/platform/define_properties","ember-metal/platform/create","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var hasES5CompliantDefineProperty = __dependency1__.hasES5CompliantDefineProperty; + var defineProperty = __dependency1__.defineProperty; + var defineProperties = __dependency2__["default"]; + var create = __dependency3__["default"]; + + /** + @module ember-metal + */ + + var hasPropertyAccessors = hasES5CompliantDefineProperty; + var canDefineNonEnumerableProperties = hasES5CompliantDefineProperty; + + /** + Platform specific methods and feature detectors needed by the framework. + + @class platform + @namespace Ember + @static + */ + + __exports__.create = create; + __exports__.defineProperty = defineProperty; + __exports__.defineProperties = defineProperties; + __exports__.hasPropertyAccessors = hasPropertyAccessors; + __exports__.canDefineNonEnumerableProperties = canDefineNonEnumerableProperties; + }); +enifed("ember-metal/platform/create", + ["exports"], + function(__exports__) { + // Remove "use strict"; from transpiled module until + // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed + // + // REMOVE_USE_STRICT: true + + /** + @class platform + @namespace Ember + @static + */ + + /** + Identical to `Object.create()`. Implements if not available natively. + + @method create + @for Ember + */ + var create; + // ES5 15.2.3.5 + // http://es5.github.com/#x15.2.3.5 + if (!(Object.create && !Object.create(null).hasOwnProperty)) { + /* jshint scripturl:true, proto:true */ + // Contributed by Brandon Benvie, October, 2012 + var createEmpty; + var supportsProto = !({'__proto__':null} instanceof Object); + // the following produces false positives + // in Opera Mini => not a reliable check + // Object.prototype.__proto__ === null + if (supportsProto || typeof document === 'undefined') { + createEmpty = function () { + return { "__proto__": null }; + }; + } else { + // In old IE __proto__ can't be used to manually set `null`, nor does + // any other method exist to make an object that inherits from nothing, + // aside from Object.prototype itself. Instead, create a new global + // object and *steal* its Object.prototype and strip it bare. This is + // used as the prototype to create nullary objects. + createEmpty = function () { + var iframe = document.createElement('iframe'); + var parent = document.body || document.documentElement; + iframe.style.display = 'none'; + parent.appendChild(iframe); + iframe.src = 'javascript:'; + var empty = iframe.contentWindow.Object.prototype; + parent.removeChild(iframe); + iframe = null; + delete empty.constructor; + delete empty.hasOwnProperty; + delete empty.propertyIsEnumerable; + delete empty.isPrototypeOf; + delete empty.toLocaleString; + delete empty.toString; + delete empty.valueOf; + + function Empty() {} + Empty.prototype = empty; + // short-circuit future calls + createEmpty = function () { + return new Empty(); + }; + return new Empty(); + }; + } + + create = Object.create = function create(prototype, properties) { + + var object; + function Type() {} // An empty constructor. + + if (prototype === null) { + object = createEmpty(); + } else { + if (typeof prototype !== "object" && typeof prototype !== "function") { + // In the native implementation `parent` can be `null` + // OR *any* `instanceof Object` (Object|Function|Array|RegExp|etc) + // Use `typeof` tho, b/c in old IE, DOM elements are not `instanceof Object` + // like they are in modern browsers. Using `Object.create` on DOM elements + // is...err...probably inappropriate, but the native version allows for it. + throw new TypeError("Object prototype may only be an Object or null"); // same msg as Chrome + } + + Type.prototype = prototype; + + object = new Type(); + } + + if (properties !== undefined) { + Object.defineProperties(object, properties); + } + + return object; + }; + } else { + create = Object.create; + } + + __exports__["default"] = create; + }); +enifed("ember-metal/platform/define_properties", + ["ember-metal/platform/define_property","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var defineProperty = __dependency1__.defineProperty; + + var defineProperties = Object.defineProperties; + + // ES5 15.2.3.7 + // http://es5.github.com/#x15.2.3.7 + if (!defineProperties) { + defineProperties = function defineProperties(object, properties) { + for (var property in properties) { + if (properties.hasOwnProperty(property) && property !== "__proto__") { + defineProperty(object, property, properties[property]); + } + } + return object; + }; + + Object.defineProperties = defineProperties; + } + + __exports__["default"] = defineProperties; + }); +enifed("ember-metal/platform/define_property", + ["exports"], + function(__exports__) { + "use strict"; + /*globals Node */ + + /** + @class platform + @namespace Ember + @static + */ + + /** + Set to true if the platform supports native getters and setters. + + @property hasPropertyAccessors + @final + */ + + /** + Identical to `Object.defineProperty()`. Implements as much functionality + as possible if not available natively. + + @method defineProperty + @param {Object} obj The object to modify + @param {String} keyName property name to modify + @param {Object} desc descriptor hash + @return {void} + */ + var defineProperty = (function checkCompliance(defineProperty) { + if (!defineProperty) return; + try { + var a = 5; + var obj = {}; + defineProperty(obj, 'a', { + configurable: true, + enumerable: true, + get: function () { + return a; + }, + set: function (v) { + a = v; + } + }); + if (obj.a !== 5) return; + obj.a = 10; + if (a !== 10) return; + + // check non-enumerability + defineProperty(obj, 'a', { + configurable: true, + enumerable: false, + writable: true, + value: true + }); + for (var key in obj) { + if (key === 'a') return; + } + + // Detects a bug in Android <3.2 where you cannot redefine a property using + // Object.defineProperty once accessors have already been set. + if (obj.a !== true) return; + + // defineProperty is compliant + return defineProperty; + } catch (e) { + // IE8 defines Object.defineProperty but calling it on an Object throws + return; + } + })(Object.defineProperty); + + var hasES5CompliantDefineProperty = !!defineProperty; + + if (hasES5CompliantDefineProperty && typeof document !== 'undefined') { + // This is for Safari 5.0, which supports Object.defineProperty, but not + // on DOM nodes. + var canDefinePropertyOnDOM = (function() { + try { + defineProperty(document.createElement('div'), 'definePropertyOnDOM', {}); + return true; + } catch(e) { } + + return false; + })(); + + if (!canDefinePropertyOnDOM) { + defineProperty = function(obj, keyName, desc) { + var isNode; + + if (typeof Node === "object") { + isNode = obj instanceof Node; + } else { + isNode = typeof obj === "object" && typeof obj.nodeType === "number" && typeof obj.nodeName === "string"; + } + + if (isNode) { + // TODO: Should we have a warning here? + return (obj[keyName] = desc.value); + } else { + return Object.defineProperty(obj, keyName, desc); + } + }; + } + } + + if (!hasES5CompliantDefineProperty) { + defineProperty = function defineProperty(obj, keyName, desc) { + if (!desc.get) { obj[keyName] = desc.value; } + }; + } + + __exports__.hasES5CompliantDefineProperty = hasES5CompliantDefineProperty; + __exports__.defineProperty = defineProperty; + }); +enifed("ember-metal/properties", + ["ember-metal/core","ember-metal/utils","ember-metal/platform","ember-metal/property_events","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + /** + @module ember-metal + */ + + var Ember = __dependency1__["default"]; + var metaFor = __dependency2__.meta; + var objectDefineProperty = __dependency3__.defineProperty; + var hasPropertyAccessors = __dependency3__.hasPropertyAccessors; + var overrideChains = __dependency4__.overrideChains; + // .......................................................... + // DESCRIPTOR + // + + /** + Objects of this type can implement an interface to respond to requests to + get and set. The default implementation handles simple properties. + + You generally won't need to create or subclass this directly. + + @class Descriptor + @namespace Ember + @private + @constructor + */ + function Descriptor() {} + + __exports__.Descriptor = Descriptor;// .......................................................... + // DEFINING PROPERTIES API + // + + function MANDATORY_SETTER_FUNCTION(name) { + return function SETTER_FUNCTION(value) { + }; + } + + __exports__.MANDATORY_SETTER_FUNCTION = MANDATORY_SETTER_FUNCTION;function DEFAULT_GETTER_FUNCTION(name) { + return function GETTER_FUNCTION() { + var meta = this['__ember_meta__']; + return meta && meta.values[name]; + }; + } + + __exports__.DEFAULT_GETTER_FUNCTION = DEFAULT_GETTER_FUNCTION;/** + NOTE: This is a low-level method used by other parts of the API. You almost + never want to call this method directly. Instead you should use + `Ember.mixin()` to define new properties. + + Defines a property on an object. This method works much like the ES5 + `Object.defineProperty()` method except that it can also accept computed + properties and other special descriptors. + + Normally this method takes only three parameters. However if you pass an + instance of `Ember.Descriptor` as the third param then you can pass an + optional value as the fourth parameter. This is often more efficient than + creating new descriptor hashes for each property. + + ## Examples + + ```javascript + // ES5 compatible mode + Ember.defineProperty(contact, 'firstName', { + writable: true, + configurable: false, + enumerable: true, + value: 'Charles' + }); + + // define a simple property + Ember.defineProperty(contact, 'lastName', undefined, 'Jolley'); + + // define a computed property + Ember.defineProperty(contact, 'fullName', Ember.computed(function() { + return this.firstName+' '+this.lastName; + }).property('firstName', 'lastName')); + ``` + + @private + @method defineProperty + @for Ember + @param {Object} obj the object to define this property on. This may be a prototype. + @param {String} keyName the name of the property + @param {Ember.Descriptor} [desc] an instance of `Ember.Descriptor` (typically a + computed property) or an ES5 descriptor. + You must provide this or `data` but not both. + @param {*} [data] something other than a descriptor, that will + become the explicit value of this property. + */ + function defineProperty(obj, keyName, desc, data, meta) { + var descs, existingDesc, watching, value; + + if (!meta) meta = metaFor(obj); + descs = meta.descs; + existingDesc = meta.descs[keyName]; + var watchEntry = meta.watching[keyName]; + + watching = watchEntry !== undefined && watchEntry > 0; + + if (existingDesc instanceof Descriptor) { + existingDesc.teardown(obj, keyName); + } + + if (desc instanceof Descriptor) { + value = desc; + + descs[keyName] = desc; + + obj[keyName] = undefined; // make enumerable + + if (desc.setup) { desc.setup(obj, keyName); } + } else { + descs[keyName] = undefined; // shadow descriptor in proto + if (desc == null) { + value = data; + + + obj[keyName] = data; + + } else { + value = desc; + + // compatibility with ES5 + objectDefineProperty(obj, keyName, desc); + } + } + + // if key is being watched, override chains that + // were initialized with the prototype + if (watching) { overrideChains(obj, keyName, meta); } + + // The `value` passed to the `didDefineProperty` hook is + // either the descriptor or data, whichever was passed. + if (obj.didDefineProperty) { obj.didDefineProperty(obj, keyName, value); } + + return this; + } + __exports__.defineProperty = defineProperty; + }); +enifed("ember-metal/property_events", + ["ember-metal/utils","ember-metal/events","ember-metal/observer_set","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var guidFor = __dependency1__.guidFor; + var tryFinally = __dependency1__.tryFinally; + var sendEvent = __dependency2__.sendEvent; + var listenersUnion = __dependency2__.listenersUnion; + var listenersDiff = __dependency2__.listenersDiff; + var ObserverSet = __dependency3__["default"]; + + var beforeObserverSet = new ObserverSet(); + var observerSet = new ObserverSet(); + var deferred = 0; + + // .......................................................... + // PROPERTY CHANGES + // + + /** + This function is called just before an object property is about to change. + It will notify any before observers and prepare caches among other things. + + Normally you will not need to call this method directly but if for some + reason you can't directly watch a property you can invoke this method + manually along with `Ember.propertyDidChange()` which you should call just + after the property value changes. + + @method propertyWillChange + @for Ember + @param {Object} obj The object with the property that will change + @param {String} keyName The property key (or path) that will change. + @return {void} + */ + function propertyWillChange(obj, keyName) { + var m = obj['__ember_meta__']; + var watching = (m && m.watching[keyName] > 0) || keyName === 'length'; + var proto = m && m.proto; + var desc = m && m.descs[keyName]; + + if (!watching) { return; } + if (proto === obj) { return; } + if (desc && desc.willChange) { desc.willChange(obj, keyName); } + dependentKeysWillChange(obj, keyName, m); + chainsWillChange(obj, keyName, m); + notifyBeforeObservers(obj, keyName); + } + + /** + This function is called just after an object property has changed. + It will notify any observers and clear caches among other things. + + Normally you will not need to call this method directly but if for some + reason you can't directly watch a property you can invoke this method + manually along with `Ember.propertyWillChange()` which you should call just + before the property value changes. + + @method propertyDidChange + @for Ember + @param {Object} obj The object with the property that will change + @param {String} keyName The property key (or path) that will change. + @return {void} + */ + function propertyDidChange(obj, keyName) { + var m = obj['__ember_meta__']; + var watching = (m && m.watching[keyName] > 0) || keyName === 'length'; + var proto = m && m.proto; + var desc = m && m.descs[keyName]; + + if (proto === obj) { return; } + + // shouldn't this mean that we're watching this key? + if (desc && desc.didChange) { desc.didChange(obj, keyName); } + if (!watching && keyName !== 'length') { return; } + + if (m && m.deps && m.deps[keyName]) { + dependentKeysDidChange(obj, keyName, m); + } + + chainsDidChange(obj, keyName, m, false); + notifyObservers(obj, keyName); + } + + var WILL_SEEN, DID_SEEN; + // called whenever a property is about to change to clear the cache of any dependent keys (and notify those properties of changes, etc...) + function dependentKeysWillChange(obj, depKey, meta) { + if (obj.isDestroying) { return; } + + var deps; + if (meta && meta.deps && (deps = meta.deps[depKey])) { + var seen = WILL_SEEN; + var top = !seen; + if (top) { seen = WILL_SEEN = {}; } + iterDeps(propertyWillChange, obj, deps, depKey, seen, meta); + if (top) { WILL_SEEN = null; } + } + } + + // called whenever a property has just changed to update dependent keys + function dependentKeysDidChange(obj, depKey, meta) { + if (obj.isDestroying) { return; } + + var deps; + if (meta && meta.deps && (deps = meta.deps[depKey])) { + var seen = DID_SEEN; + var top = !seen; + if (top) { seen = DID_SEEN = {}; } + iterDeps(propertyDidChange, obj, deps, depKey, seen, meta); + if (top) { DID_SEEN = null; } + } + } + + function keysOf(obj) { + var keys = []; + for (var key in obj) keys.push(key); + return keys; + } + + function iterDeps(method, obj, deps, depKey, seen, meta) { + var keys, key, i, desc; + var guid = guidFor(obj); + var current = seen[guid]; + if (!current) current = seen[guid] = {}; + if (current[depKey]) return; + current[depKey] = true; + + if (deps) { + keys = keysOf(deps); + var descs = meta.descs; + for (i=0; i Ember + if (root === null && !isPath(path)) { + return get(Ember.lookup, path); + } + + // detect complicated paths and normalize them + hasThis = pathHasThis(path); + + if (!root || hasThis) { + tuple = normalizeTuple(root, path); + root = tuple[0]; + path = tuple[1]; + tuple.length = 0; + } + + parts = path.split("."); + len = parts.length; + for (idx = 0; root != null && idx < len; idx++) { + root = get(root, parts[idx], true); + if (root && root.isDestroyed) { return undefined; } + } + return root; + } + + function getWithDefault(root, key, defaultValue) { + var value = get(root, key); + + if (value === undefined) { return defaultValue; } + return value; + } + + __exports__.getWithDefault = getWithDefault;__exports__["default"] = get; + __exports__.get = get; + __exports__.normalizeTuple = normalizeTuple; + __exports__._getPath = _getPath; + }); +enifed("ember-metal/property_set", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_events","ember-metal/properties","ember-metal/error","ember-metal/path_cache","ember-metal/platform","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var getPath = __dependency2__._getPath; + var propertyWillChange = __dependency3__.propertyWillChange; + var propertyDidChange = __dependency3__.propertyDidChange; + var defineProperty = __dependency4__.defineProperty; + var EmberError = __dependency5__["default"]; + var isPath = __dependency6__.isPath; + var hasPropertyAccessors = __dependency7__.hasPropertyAccessors; + + var IS_GLOBAL = /^([A-Z$]|([0-9][A-Z$]))/; + + /** + Sets the value of a property on an object, respecting computed properties + and notifying observers and other listeners of the change. If the + property is not defined but the object implements the `setUnknownProperty` + method then that will be invoked as well. + + @method set + @for Ember + @param {Object} obj The object to modify. + @param {String} keyName The property key to set + @param {Object} value The value to set + @return {Object} the passed value. + */ + var set = function set(obj, keyName, value, tolerant) { + if (typeof obj === 'string') { + value = keyName; + keyName = obj; + obj = null; + } + + + if (!obj) { + return setPath(obj, keyName, value, tolerant); + } + + var meta = obj['__ember_meta__']; + var desc = meta && meta.descs[keyName]; + var isUnknown, currentValue; + + if (desc === undefined && isPath(keyName)) { + return setPath(obj, keyName, value, tolerant); + } + + + if (desc !== undefined) { + desc.set(obj, keyName, value); + } else { + + if (typeof obj === 'object' && obj !== null && value !== undefined && obj[keyName] === value) { + return value; + } + + isUnknown = 'object' === typeof obj && !(keyName in obj); + + // setUnknownProperty is called if `obj` is an object, + // the property does not already exist, and the + // `setUnknownProperty` method exists on the object + if (isUnknown && 'function' === typeof obj.setUnknownProperty) { + obj.setUnknownProperty(keyName, value); + } else if (meta && meta.watching[keyName] > 0) { + + currentValue = obj[keyName]; + + // only trigger a change if the value has changed + if (value !== currentValue) { + propertyWillChange(obj, keyName); + + obj[keyName] = value; + + propertyDidChange(obj, keyName); + } + } else { + obj[keyName] = value; + } + } + return value; + }; + + // Currently used only by Ember Data tests + // ES6TODO: Verify still true + if (Ember.config.overrideAccessors) { + Ember.set = set; + Ember.config.overrideAccessors(); + set = Ember.set; + } + + function setPath(root, path, value, tolerant) { + var keyName; + + // get the last part of the path + keyName = path.slice(path.lastIndexOf('.') + 1); + + // get the first part of the part + path = (path === keyName) ? keyName : path.slice(0, path.length-(keyName.length+1)); + + // unless the path is this, look up the first part to + // get the root + if (path !== 'this') { + root = getPath(root, path); + } + + if (!keyName || keyName.length === 0) { + throw new EmberError('Property set failed: You passed an empty path'); + } + + if (!root) { + if (tolerant) { return; } + else { throw new EmberError('Property set failed: object in path "'+path+'" could not be found or was destroyed.'); } + } + + return set(root, keyName, value); + } + + /** + Error-tolerant form of `Ember.set`. Will not blow up if any part of the + chain is `undefined`, `null`, or destroyed. + + This is primarily used when syncing bindings, which may try to update after + an object has been destroyed. + + @method trySet + @for Ember + @param {Object} obj The object to modify. + @param {String} path The property path to set + @param {Object} value The value to set + */ + function trySet(root, path, value) { + return set(root, path, value, true); + } + + __exports__.trySet = trySet;__exports__.set = set; + }); +enifed("ember-metal/run_loop", + ["ember-metal/core","ember-metal/utils","ember-metal/array","ember-metal/property_events","backburner","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var apply = __dependency2__.apply; + var GUID_KEY = __dependency2__.GUID_KEY; + var indexOf = __dependency3__.indexOf; + var beginPropertyChanges = __dependency4__.beginPropertyChanges; + var endPropertyChanges = __dependency4__.endPropertyChanges; + var Backburner = __dependency5__["default"]; + + function onBegin(current) { + run.currentRunLoop = current; + } + + function onEnd(current, next) { + run.currentRunLoop = next; + } + + // ES6TODO: should Backburner become es6? + var backburner = new Backburner(['sync', 'actions', 'destroy'], { + GUID_KEY: GUID_KEY, + sync: { + before: beginPropertyChanges, + after: endPropertyChanges + }, + defaultQueue: 'actions', + onBegin: onBegin, + onEnd: onEnd, + onErrorTarget: Ember, + onErrorMethod: 'onerror' + }); + var slice = [].slice; + var concat = [].concat; + + // .......................................................... + // run - this is ideally the only public API the dev sees + // + + /** + Runs the passed target and method inside of a RunLoop, ensuring any + deferred actions including bindings and views updates are flushed at the + end. + + Normally you should not need to invoke this method yourself. However if + you are implementing raw event handlers when interfacing with other + libraries or plugins, you should probably wrap all of your code inside this + call. + + ```javascript + run(function() { + // code to be execute within a RunLoop + }); + ``` + + @class run + @namespace Ember + @static + @constructor + @param {Object} [target] target of method to call + @param {Function|String} method Method to invoke. + May be a function or a string. If you pass a string + then it will be looked up on the passed target. + @param {Object} [args*] Any additional arguments you wish to pass to the method. + @return {Object} return value from invoking the passed function. + */ + __exports__["default"] = run; + function run() { + return backburner.run.apply(backburner, arguments); + } + + /** + If no run-loop is present, it creates a new one. If a run loop is + present it will queue itself to run on the existing run-loops action + queue. + + Please note: This is not for normal usage, and should be used sparingly. + + If invoked when not within a run loop: + + ```javascript + run.join(function() { + // creates a new run-loop + }); + ``` + + Alternatively, if called within an existing run loop: + + ```javascript + run(function() { + // creates a new run-loop + run.join(function() { + // joins with the existing run-loop, and queues for invocation on + // the existing run-loops action queue. + }); + }); + ``` + + @method join + @namespace Ember + @param {Object} [target] target of method to call + @param {Function|String} method Method to invoke. + May be a function or a string. If you pass a string + then it will be looked up on the passed target. + @param {Object} [args*] Any additional arguments you wish to pass to the method. + @return {Object} Return value from invoking the passed function. Please note, + when called within an existing loop, no return value is possible. + */ + run.join = function(target, method /* args */) { + if (!run.currentRunLoop) { + return Ember.run.apply(Ember, arguments); + } + + var args = slice.call(arguments); + args.unshift('actions'); + run.schedule.apply(run, args); + }; + + /** + Provides a useful utility for when integrating with non-Ember libraries + that provide asynchronous callbacks. + + Ember utilizes a run-loop to batch and coalesce changes. This works by + marking the start and end of Ember-related Javascript execution. + + When using events such as a View's click handler, Ember wraps the event + handler in a run-loop, but when integrating with non-Ember libraries this + can be tedious. + + For example, the following is rather verbose but is the correct way to combine + third-party events and Ember code. + + ```javascript + var that = this; + jQuery(window).on('resize', function(){ + run(function(){ + that.handleResize(); + }); + }); + ``` + + To reduce the boilerplate, the following can be used to construct a + run-loop-wrapped callback handler. + + ```javascript + jQuery(window).on('resize', run.bind(this, this.handleResize)); + ``` + + @method bind + @namespace Ember + @param {Object} [target] target of method to call + @param {Function|String} method Method to invoke. + May be a function or a string. If you pass a string + then it will be looked up on the passed target. + @param {Object} [args*] Any additional arguments you wish to pass to the method. + @return {Object} return value from invoking the passed function. Please note, + when called within an existing loop, no return value is possible. + @since 1.4.0 + */ + run.bind = function(target, method /* args*/) { + var args = slice.call(arguments); + return function() { + return run.join.apply(run, args.concat(slice.call(arguments))); + }; + }; + + run.backburner = backburner; + run.currentRunLoop = null; + run.queues = backburner.queueNames; + + /** + Begins a new RunLoop. Any deferred actions invoked after the begin will + be buffered until you invoke a matching call to `run.end()`. This is + a lower-level way to use a RunLoop instead of using `run()`. + + ```javascript + run.begin(); + // code to be execute within a RunLoop + run.end(); + ``` + + @method begin + @return {void} + */ + run.begin = function() { + backburner.begin(); + }; + + /** + Ends a RunLoop. This must be called sometime after you call + `run.begin()` to flush any deferred actions. This is a lower-level way + to use a RunLoop instead of using `run()`. + + ```javascript + run.begin(); + // code to be execute within a RunLoop + run.end(); + ``` + + @method end + @return {void} + */ + run.end = function() { + backburner.end(); + }; + + /** + Array of named queues. This array determines the order in which queues + are flushed at the end of the RunLoop. You can define your own queues by + simply adding the queue name to this array. Normally you should not need + to inspect or modify this property. + + @property queues + @type Array + @default ['sync', 'actions', 'destroy'] + */ + + /** + Adds the passed target/method and any optional arguments to the named + queue to be executed at the end of the RunLoop. If you have not already + started a RunLoop when calling this method one will be started for you + automatically. + + At the end of a RunLoop, any methods scheduled in this way will be invoked. + Methods will be invoked in an order matching the named queues defined in + the `run.queues` property. + + ```javascript + run.schedule('sync', this, function() { + // this will be executed in the first RunLoop queue, when bindings are synced + console.log("scheduled on sync queue"); + }); + + run.schedule('actions', this, function() { + // this will be executed in the 'actions' queue, after bindings have synced. + console.log("scheduled on actions queue"); + }); + + // Note the functions will be run in order based on the run queues order. + // Output would be: + // scheduled on sync queue + // scheduled on actions queue + ``` + + @method schedule + @param {String} queue The name of the queue to schedule against. + Default queues are 'sync' and 'actions' + @param {Object} [target] target object to use as the context when invoking a method. + @param {String|Function} method The method to invoke. If you pass a string it + will be resolved on the target object at the time the scheduled item is + invoked allowing you to change the target function. + @param {Object} [arguments*] Optional arguments to be passed to the queued method. + @return {void} + */ + run.schedule = function(queue, target, method) { + checkAutoRun(); + backburner.schedule.apply(backburner, arguments); + }; + + // Used by global test teardown + run.hasScheduledTimers = function() { + return backburner.hasTimers(); + }; + + // Used by global test teardown + run.cancelTimers = function () { + backburner.cancelTimers(); + }; + + /** + Immediately flushes any events scheduled in the 'sync' queue. Bindings + use this queue so this method is a useful way to immediately force all + bindings in the application to sync. + + You should call this method anytime you need any changed state to propagate + throughout the app immediately without repainting the UI (which happens + in the later 'render' queue added by the `ember-views` package). + + ```javascript + run.sync(); + ``` + + @method sync + @return {void} + */ + run.sync = function() { + if (backburner.currentInstance) { + backburner.currentInstance.queues.sync.flush(); + } + }; + + /** + Invokes the passed target/method and optional arguments after a specified + period of time. The last parameter of this method must always be a number + of milliseconds. + + You should use this method whenever you need to run some action after a + period of time instead of using `setTimeout()`. This method will ensure that + items that expire during the same script execution cycle all execute + together, which is often more efficient than using a real setTimeout. + + ```javascript + run.later(myContext, function() { + // code here will execute within a RunLoop in about 500ms with this == myContext + }, 500); + ``` + + @method later + @param {Object} [target] target of method to invoke + @param {Function|String} method The method to invoke. + If you pass a string it will be resolved on the + target at the time the method is invoked. + @param {Object} [args*] Optional arguments to pass to the timeout. + @param {Number} wait Number of milliseconds to wait. + @return {Object} Timer information for use in cancelling, see `run.cancel`. + */ + run.later = function(/*target, method*/) { + return backburner.later.apply(backburner, arguments); + }; + + /** + Schedule a function to run one time during the current RunLoop. This is equivalent + to calling `scheduleOnce` with the "actions" queue. + + @method once + @param {Object} [target] The target of the method to invoke. + @param {Function|String} method The method to invoke. + If you pass a string it will be resolved on the + target at the time the method is invoked. + @param {Object} [args*] Optional arguments to pass to the timeout. + @return {Object} Timer information for use in cancelling, see `run.cancel`. + */ + run.once = function(target, method) { + checkAutoRun(); + var args = slice.call(arguments); + args.unshift('actions'); + return apply(backburner, backburner.scheduleOnce, args); + }; + + /** + Schedules a function to run one time in a given queue of the current RunLoop. + Calling this method with the same queue/target/method combination will have + no effect (past the initial call). + + Note that although you can pass optional arguments these will not be + considered when looking for duplicates. New arguments will replace previous + calls. + + ```javascript + run(function() { + var sayHi = function() { console.log('hi'); } + run.scheduleOnce('afterRender', myContext, sayHi); + run.scheduleOnce('afterRender', myContext, sayHi); + // sayHi will only be executed once, in the afterRender queue of the RunLoop + }); + ``` + + Also note that passing an anonymous function to `run.scheduleOnce` will + not prevent additional calls with an identical anonymous function from + scheduling the items multiple times, e.g.: + + ```javascript + function scheduleIt() { + run.scheduleOnce('actions', myContext, function() { console.log("Closure"); }); + } + scheduleIt(); + scheduleIt(); + // "Closure" will print twice, even though we're using `run.scheduleOnce`, + // because the function we pass to it is anonymous and won't match the + // previously scheduled operation. + ``` + + Available queues, and their order, can be found at `run.queues` + + @method scheduleOnce + @param {String} [queue] The name of the queue to schedule against. Default queues are 'sync' and 'actions'. + @param {Object} [target] The target of the method to invoke. + @param {Function|String} method The method to invoke. + If you pass a string it will be resolved on the + target at the time the method is invoked. + @param {Object} [args*] Optional arguments to pass to the timeout. + @return {Object} Timer information for use in cancelling, see `run.cancel`. + */ + run.scheduleOnce = function(/*queue, target, method*/) { + checkAutoRun(); + return backburner.scheduleOnce.apply(backburner, arguments); + }; + + /** + Schedules an item to run from within a separate run loop, after + control has been returned to the system. This is equivalent to calling + `run.later` with a wait time of 1ms. + + ```javascript + run.next(myContext, function() { + // code to be executed in the next run loop, + // which will be scheduled after the current one + }); + ``` + + Multiple operations scheduled with `run.next` will coalesce + into the same later run loop, along with any other operations + scheduled by `run.later` that expire right around the same + time that `run.next` operations will fire. + + Note that there are often alternatives to using `run.next`. + For instance, if you'd like to schedule an operation to happen + after all DOM element operations have completed within the current + run loop, you can make use of the `afterRender` run loop queue (added + by the `ember-views` package, along with the preceding `render` queue + where all the DOM element operations happen). Example: + + ```javascript + App.MyCollectionView = Ember.CollectionView.extend({ + didInsertElement: function() { + run.scheduleOnce('afterRender', this, 'processChildElements'); + }, + processChildElements: function() { + // ... do something with collectionView's child view + // elements after they've finished rendering, which + // can't be done within the CollectionView's + // `didInsertElement` hook because that gets run + // before the child elements have been added to the DOM. + } + }); + ``` + + One benefit of the above approach compared to using `run.next` is + that you will be able to perform DOM/CSS operations before unprocessed + elements are rendered to the screen, which may prevent flickering or + other artifacts caused by delaying processing until after rendering. + + The other major benefit to the above approach is that `run.next` + introduces an element of non-determinism, which can make things much + harder to test, due to its reliance on `setTimeout`; it's much harder + to guarantee the order of scheduled operations when they are scheduled + outside of the current run loop, i.e. with `run.next`. + + @method next + @param {Object} [target] target of method to invoke + @param {Function|String} method The method to invoke. + If you pass a string it will be resolved on the + target at the time the method is invoked. + @param {Object} [args*] Optional arguments to pass to the timeout. + @return {Object} Timer information for use in cancelling, see `run.cancel`. + */ + run.next = function() { + var args = slice.call(arguments); + args.push(1); + return apply(backburner, backburner.later, args); + }; + + /** + Cancels a scheduled item. Must be a value returned by `run.later()`, + `run.once()`, `run.next()`, `run.debounce()`, or + `run.throttle()`. + + ```javascript + var runNext = run.next(myContext, function() { + // will not be executed + }); + run.cancel(runNext); + + var runLater = run.later(myContext, function() { + // will not be executed + }, 500); + run.cancel(runLater); + + var runOnce = run.once(myContext, function() { + // will not be executed + }); + run.cancel(runOnce); + + var throttle = run.throttle(myContext, function() { + // will not be executed + }, 1, false); + run.cancel(throttle); + + var debounce = run.debounce(myContext, function() { + // will not be executed + }, 1); + run.cancel(debounce); + + var debounceImmediate = run.debounce(myContext, function() { + // will be executed since we passed in true (immediate) + }, 100, true); + // the 100ms delay until this method can be called again will be cancelled + run.cancel(debounceImmediate); + ``` + + @method cancel + @param {Object} timer Timer object to cancel + @return {Boolean} true if cancelled or false/undefined if it wasn't found + */ + run.cancel = function(timer) { + return backburner.cancel(timer); + }; + + /** + Delay calling the target method until the debounce period has elapsed + with no additional debounce calls. If `debounce` is called again before + the specified time has elapsed, the timer is reset and the entire period + must pass again before the target method is called. + + This method should be used when an event may be called multiple times + but the action should only be called once when the event is done firing. + A common example is for scroll events where you only want updates to + happen once scrolling has ceased. + + ```javascript + var myFunc = function() { console.log(this.name + ' ran.'); }; + var myContext = {name: 'debounce'}; + + run.debounce(myContext, myFunc, 150); + + // less than 150ms passes + + run.debounce(myContext, myFunc, 150); + + // 150ms passes + // myFunc is invoked with context myContext + // console logs 'debounce ran.' one time. + ``` + + Immediate allows you to run the function immediately, but debounce + other calls for this function until the wait time has elapsed. If + `debounce` is called again before the specified time has elapsed, + the timer is reset and the entire period must pass again before + the method can be called again. + + ```javascript + var myFunc = function() { console.log(this.name + ' ran.'); }; + var myContext = {name: 'debounce'}; + + run.debounce(myContext, myFunc, 150, true); + + // console logs 'debounce ran.' one time immediately. + // 100ms passes + + run.debounce(myContext, myFunc, 150, true); + + // 150ms passes and nothing else is logged to the console and + // the debouncee is no longer being watched + + run.debounce(myContext, myFunc, 150, true); + + // console logs 'debounce ran.' one time immediately. + // 150ms passes and nothing else is logged to the console and + // the debouncee is no longer being watched + + ``` + + @method debounce + @param {Object} [target] target of method to invoke + @param {Function|String} method The method to invoke. + May be a function or a string. If you pass a string + then it will be looked up on the passed target. + @param {Object} [args*] Optional arguments to pass to the timeout. + @param {Number} wait Number of milliseconds to wait. + @param {Boolean} immediate Trigger the function on the leading instead + of the trailing edge of the wait interval. Defaults to false. + @return {Array} Timer information for use in cancelling, see `run.cancel`. + */ + run.debounce = function() { + return backburner.debounce.apply(backburner, arguments); + }; + + /** + Ensure that the target method is never called more frequently than + the specified spacing period. The target method is called immediately. + + ```javascript + var myFunc = function() { console.log(this.name + ' ran.'); }; + var myContext = {name: 'throttle'}; + + run.throttle(myContext, myFunc, 150); + // myFunc is invoked with context myContext + // console logs 'throttle ran.' + + // 50ms passes + run.throttle(myContext, myFunc, 150); + + // 50ms passes + run.throttle(myContext, myFunc, 150); + + // 150ms passes + run.throttle(myContext, myFunc, 150); + // myFunc is invoked with context myContext + // console logs 'throttle ran.' + ``` + + @method throttle + @param {Object} [target] target of method to invoke + @param {Function|String} method The method to invoke. + May be a function or a string. If you pass a string + then it will be looked up on the passed target. + @param {Object} [args*] Optional arguments to pass to the timeout. + @param {Number} spacing Number of milliseconds to space out requests. + @param {Boolean} immediate Trigger the function on the leading instead + of the trailing edge of the wait interval. Defaults to true. + @return {Array} Timer information for use in cancelling, see `run.cancel`. + */ + run.throttle = function() { + return backburner.throttle.apply(backburner, arguments); + }; + + // Make sure it's not an autorun during testing + function checkAutoRun() { + if (!run.currentRunLoop) { + } + } + + /** + Add a new named queue after the specified queue. + + The queue to add will only be added once. + + @method _addQueue + @param {String} name the name of the queue to add. + @param {String} after the name of the queue to add after. + @private + */ + run._addQueue = function(name, after) { + if (indexOf.call(run.queues, name) === -1) { + run.queues.splice(indexOf.call(run.queues, after)+1, 0, name); + } + }; + }); +enifed("ember-metal/set_properties", + ["ember-metal/property_events","ember-metal/property_set","ember-metal/keys","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var changeProperties = __dependency1__.changeProperties; + var set = __dependency2__.set; + var keys = __dependency3__["default"]; + + /** + Set a list of properties on an object. These properties are set inside + a single `beginPropertyChanges` and `endPropertyChanges` batch, so + observers will be buffered. + + ```javascript + var anObject = Ember.Object.create(); + + anObject.setProperties({ + firstName: 'Stanley', + lastName: 'Stuart', + age: 21 + }); + ``` + + @method setProperties + @param obj + @param {Object} properties + @return obj + */ + __exports__["default"] = function setProperties(obj, properties) { + if (!properties || typeof properties !== "object") { return obj; } + changeProperties(function() { + var props = keys(properties); + var propertyName; + + for (var i = 0, l = props.length; i < l; i++) { + propertyName = props[i]; + + set(obj, propertyName, properties[propertyName]); + } + }); + return obj; + } + }); +enifed("ember-metal/utils", + ["ember-metal/core","ember-metal/platform","ember-metal/array","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var o_defineProperty = __dependency2__.defineProperty; + var canDefineNonEnumerableProperties = __dependency2__.canDefineNonEnumerableProperties; + var hasPropertyAccessors = __dependency2__.hasPropertyAccessors; + var create = __dependency2__.create; + + var forEach = __dependency3__.forEach; + + /** + @module ember-metal + */ + + /** + Previously we used `Ember.$.uuid`, however `$.uuid` has been removed from + jQuery master. We'll just bootstrap our own uuid now. + + @private + @return {Number} the uuid + */ + var _uuid = 0; + + /** + Generates a universally unique identifier. This method + is used internally by Ember for assisting with + the generation of GUID's and other unique identifiers + such as `bind-attr` data attributes. + + @public + @return {Number} [description] + */ + function uuid() { + return ++_uuid; + } + + __exports__.uuid = uuid;/** + Prefix used for guids through out Ember. + @private + @property GUID_PREFIX + @for Ember + @type String + @final + */ + var GUID_PREFIX = 'ember'; + + var o_create = create; + // Used for guid generation... + var numberCache = []; + var stringCache = {}; + + /** + Strongly hint runtimes to intern the provided string. + + When do I need to use this function? + + For the most part, never. Pre-mature optimization is bad, and often the + runtime does exactly what you need it to, and more often the trade-off isn't + worth it. + + Why? + + Runtimes store strings in at least 2 different representations: + Ropes and Symbols (interned strings). The Rope provides a memory efficient + data-structure for strings created from concatenation or some other string + manipulation like splitting. + + Unfortunately checking equality of different ropes can be quite costly as + runtimes must resort to clever string comparison algorithims. These + algorithims typically cost in proportion to the length of the string. + Luckily, this is where the Symbols (interned strings) shine. As Symbols are + unique by their string content, equality checks can be done by pointer + comparision. + + How do I know if my string is a rope or symbol? + + Typically (warning general sweeping statement, but truthy in runtimes at + present) static strings created as part of the JS source are interned. + Strings often used for comparisions can be interned at runtime if some + criteria are met. One of these criteria can be the size of the entire rope. + For example, in chrome 38 a rope longer then 12 characters will not + intern, nor will segments of that rope. + + Some numbers: http://jsperf.com/eval-vs-keys/8 + + Known Trick™ + + @private + @return {String} interned version of the provided string + */ + function intern(str) { + var obj = {}; + obj[str] = 1; + for (var key in obj) { + if (key === str) return key; + } + return str; + } + + /** + A unique key used to assign guids and other private metadata to objects. + If you inspect an object in your browser debugger you will often see these. + They can be safely ignored. + + On browsers that support it, these properties are added with enumeration + disabled so they won't show up when you iterate over your properties. + + @private + @property GUID_KEY + @for Ember + @type String + @final + */ + var GUID_KEY = intern('__ember' + (+ new Date())); + + var GUID_DESC = { + writable: false, + configurable: false, + enumerable: false, + value: null + }; + + /** + Generates a new guid, optionally saving the guid to the object that you + pass in. You will rarely need to use this method. Instead you should + call `Ember.guidFor(obj)`, which return an existing guid if available. + + @private + @method generateGuid + @for Ember + @param {Object} [obj] Object the guid will be used for. If passed in, the guid will + be saved on the object and reused whenever you pass the same object + again. + + If no object is passed, just generate a new guid. + @param {String} [prefix] Prefix to place in front of the guid. Useful when you want to + separate the guid into separate namespaces. + @return {String} the guid + */ + function generateGuid(obj, prefix) { + if (!prefix) prefix = GUID_PREFIX; + var ret = (prefix + uuid()); + if (obj) { + if (obj[GUID_KEY] === null) { + obj[GUID_KEY] = ret; + } else { + GUID_DESC.value = ret; + o_defineProperty(obj, GUID_KEY, GUID_DESC); + } + } + return ret; + } + + __exports__.generateGuid = generateGuid;/** + Returns a unique id for the object. If the object does not yet have a guid, + one will be assigned to it. You can call this on any object, + `Ember.Object`-based or not, but be aware that it will add a `_guid` + property. + + You can also use this method on DOM Element objects. + + @private + @method guidFor + @for Ember + @param {Object} obj any object, string, number, Element, or primitive + @return {String} the unique guid for this instance. + */ + function guidFor(obj) { + + // special cases where we don't want to add a key to object + if (obj === undefined) return "(undefined)"; + if (obj === null) return "(null)"; + + var ret; + var type = typeof obj; + + // Don't allow prototype changes to String etc. to change the guidFor + switch(type) { + case 'number': + ret = numberCache[obj]; + if (!ret) ret = numberCache[obj] = 'nu'+obj; + return ret; + + case 'string': + ret = stringCache[obj]; + if (!ret) ret = stringCache[obj] = 'st' + uuid(); + return ret; + + case 'boolean': + return obj ? '(true)' : '(false)'; + + default: + if (obj[GUID_KEY]) return obj[GUID_KEY]; + if (obj === Object) return '(Object)'; + if (obj === Array) return '(Array)'; + ret = GUID_PREFIX + uuid(); + + if (obj[GUID_KEY] === null) { + obj[GUID_KEY] = ret; + } else { + GUID_DESC.value = ret; + o_defineProperty(obj, GUID_KEY, GUID_DESC); + } + return ret; + } + } + + __exports__.guidFor = guidFor;// .......................................................... + // META + // + + var META_DESC = { + writable: true, + configurable: false, + enumerable: false, + value: null + }; + + function Meta(obj) { + this.descs = {}; + this.watching = {}; + this.cache = {}; + this.cacheMeta = {}; + this.source = obj; + } + + Meta.prototype = { + descs: null, + deps: null, + watching: null, + listeners: null, + cache: null, + cacheMeta: null, + source: null, + mixins: null, + bindings: null, + chains: null, + chainWatchers: null, + values: null, + proto: null + }; + + if (!canDefineNonEnumerableProperties) { + // on platforms that don't support enumerable false + // make meta fail jQuery.isPlainObject() to hide from + // jQuery.extend() by having a property that fails + // hasOwnProperty check. + Meta.prototype.__preventPlainObject__ = true; + + // Without non-enumerable properties, meta objects will be output in JSON + // unless explicitly suppressed + Meta.prototype.toJSON = function () { }; + } + + // Placeholder for non-writable metas. + var EMPTY_META = new Meta(null); + + + /** + Retrieves the meta hash for an object. If `writable` is true ensures the + hash is writable for this object as well. + + The meta object contains information about computed property descriptors as + well as any watched properties and other information. You generally will + not access this information directly but instead work with higher level + methods that manipulate this hash indirectly. + + @method meta + @for Ember + @private + + @param {Object} obj The object to retrieve meta for + @param {Boolean} [writable=true] Pass `false` if you do not intend to modify + the meta hash, allowing the method to avoid making an unnecessary copy. + @return {Object} the meta hash for an object + */ + function meta(obj, writable) { + + var ret = obj['__ember_meta__']; + if (writable===false) return ret || EMPTY_META; + + if (!ret) { + if (canDefineNonEnumerableProperties) o_defineProperty(obj, '__ember_meta__', META_DESC); + + ret = new Meta(obj); + + + obj['__ember_meta__'] = ret; + + // make sure we don't accidentally try to create constructor like desc + ret.descs.constructor = null; + + } else if (ret.source !== obj) { + if (canDefineNonEnumerableProperties) o_defineProperty(obj, '__ember_meta__', META_DESC); + + ret = o_create(ret); + ret.descs = o_create(ret.descs); + ret.watching = o_create(ret.watching); + ret.cache = {}; + ret.cacheMeta = {}; + ret.source = obj; + + + obj['__ember_meta__'] = ret; + } + return ret; + } + + function getMeta(obj, property) { + var _meta = meta(obj, false); + return _meta[property]; + } + + __exports__.getMeta = getMeta;function setMeta(obj, property, value) { + var _meta = meta(obj, true); + _meta[property] = value; + return value; + } + + __exports__.setMeta = setMeta;/** + @deprecated + @private + + In order to store defaults for a class, a prototype may need to create + a default meta object, which will be inherited by any objects instantiated + from the class's constructor. + + However, the properties of that meta object are only shallow-cloned, + so if a property is a hash (like the event system's `listeners` hash), + it will by default be shared across all instances of that class. + + This method allows extensions to deeply clone a series of nested hashes or + other complex objects. For instance, the event system might pass + `['listeners', 'foo:change', 'ember157']` to `prepareMetaPath`, which will + walk down the keys provided. + + For each key, if the key does not exist, it is created. If it already + exists and it was inherited from its constructor, the constructor's + key is cloned. + + You can also pass false for `writable`, which will simply return + undefined if `prepareMetaPath` discovers any part of the path that + shared or undefined. + + @method metaPath + @for Ember + @param {Object} obj The object whose meta we are examining + @param {Array} path An array of keys to walk down + @param {Boolean} writable whether or not to create a new meta + (or meta property) if one does not already exist or if it's + shared with its constructor + */ + function metaPath(obj, path, writable) { + var _meta = meta(obj, writable); + var keyName, value; + + for (var i=0, l=path.length; i 1) { + watching[keyName]--; + } + } + + __exports__.unwatchKey = unwatchKey; + }); +enifed("ember-metal/watch_path", + ["ember-metal/utils","ember-metal/chains","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var meta = __dependency1__.meta; + var typeOf = __dependency1__.typeOf; + var ChainNode = __dependency2__.ChainNode; + + var metaFor = meta; + + // get the chains for the current object. If the current object has + // chains inherited from the proto they will be cloned and reconfigured for + // the current object. + function chainsFor(obj, meta) { + var m = meta || metaFor(obj); + var ret = m.chains; + if (!ret) { + ret = m.chains = new ChainNode(null, null, obj); + } else if (ret.value() !== obj) { + ret = m.chains = ret.copy(obj); + } + return ret; + } + + function watchPath(obj, keyPath, meta) { + // can't watch length on Array - it is special... + if (keyPath === 'length' && typeOf(obj) === 'array') { return; } + + var m = meta || metaFor(obj); + var watching = m.watching; + + if (!watching[keyPath]) { // activate watching first time + watching[keyPath] = 1; + chainsFor(obj, m).add(keyPath); + } else { + watching[keyPath] = (watching[keyPath] || 0) + 1; + } + } + + __exports__.watchPath = watchPath;function unwatchPath(obj, keyPath, meta) { + var m = meta || metaFor(obj); + var watching = m.watching; + + if (watching[keyPath] === 1) { + watching[keyPath] = 0; + chainsFor(obj, m).remove(keyPath); + } else if (watching[keyPath] > 1) { + watching[keyPath]--; + } + } + + __exports__.unwatchPath = unwatchPath; + }); +enifed("ember-metal/watching", + ["ember-metal/utils","ember-metal/chains","ember-metal/watch_key","ember-metal/watch_path","ember-metal/path_cache","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + /** + @module ember-metal + */ + + var meta = __dependency1__.meta; + var GUID_KEY = __dependency1__.GUID_KEY; + var typeOf = __dependency1__.typeOf; + var generateGuid = __dependency1__.generateGuid; + var removeChainWatcher = __dependency2__.removeChainWatcher; + var flushPendingChains = __dependency2__.flushPendingChains; + var watchKey = __dependency3__.watchKey; + var unwatchKey = __dependency3__.unwatchKey; + var watchPath = __dependency4__.watchPath; + var unwatchPath = __dependency4__.unwatchPath; + + var metaFor = meta; // utils.js + var isPath = __dependency5__.isPath; + + /** + Starts watching a property on an object. Whenever the property changes, + invokes `Ember.propertyWillChange` and `Ember.propertyDidChange`. This is the + primitive used by observers and dependent keys; usually you will never call + this method directly but instead use higher level methods like + `Ember.addObserver()` + + @private + @method watch + @for Ember + @param obj + @param {String} keyName + */ + function watch(obj, _keyPath, m) { + // can't watch length on Array - it is special... + if (_keyPath === 'length' && typeOf(obj) === 'array') { return; } + + if (!isPath(_keyPath)) { + watchKey(obj, _keyPath, m); + } else { + watchPath(obj, _keyPath, m); + } + } + + __exports__.watch = watch; + + function isWatching(obj, key) { + var meta = obj['__ember_meta__']; + return (meta && meta.watching[key]) > 0; + } + + __exports__.isWatching = isWatching;watch.flushPending = flushPendingChains; + + function unwatch(obj, _keyPath, m) { + // can't watch length on Array - it is special... + if (_keyPath === 'length' && typeOf(obj) === 'array') { return; } + + if (!isPath(_keyPath)) { + unwatchKey(obj, _keyPath, m); + } else { + unwatchPath(obj, _keyPath, m); + } + } + + __exports__.unwatch = unwatch;/** + Call on an object when you first beget it from another object. This will + setup any chained watchers on the object instance as needed. This method is + safe to call multiple times. + + @private + @method rewatch + @for Ember + @param obj + */ + function rewatch(obj) { + var m = obj['__ember_meta__'], chains = m && m.chains; + + // make sure the object has its own guid. + if (GUID_KEY in obj && !obj.hasOwnProperty(GUID_KEY)) { + generateGuid(obj); + } + + // make sure any chained watchers update. + if (chains && chains.value() !== obj) { + m.chains = chains.copy(obj); + } + } + + __exports__.rewatch = rewatch;var NODE_STACK = []; + + /** + Tears down the meta on an object so that it can be garbage collected. + Multiple calls will have no effect. + + @method destroy + @for Ember + @param {Object} obj the object to destroy + @return {void} + */ + function destroy(obj) { + var meta = obj['__ember_meta__'], node, nodes, key, nodeObject; + if (meta) { + obj['__ember_meta__'] = null; + // remove chainWatchers to remove circular references that would prevent GC + node = meta.chains; + if (node) { + NODE_STACK.push(node); + // process tree + while (NODE_STACK.length > 0) { + node = NODE_STACK.pop(); + // push children + nodes = node._chains; + if (nodes) { + for (key in nodes) { + if (nodes.hasOwnProperty(key)) { + NODE_STACK.push(nodes[key]); + } + } + } + // remove chainWatcher in node object + if (node._watching) { + nodeObject = node._object; + if (nodeObject) { + removeChainWatcher(nodeObject, node._key, node); + } + } + } + } + } + } + + __exports__.destroy = destroy; + }); +enifed("ember-routing-handlebars", + ["ember-metal/core","ember-handlebars","ember-routing/system/router","ember-routing-handlebars/helpers/shared","ember-routing-handlebars/helpers/link_to","ember-routing-handlebars/helpers/outlet","ember-routing-handlebars/helpers/render","ember-routing-handlebars/helpers/action","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + /** + Ember Routing Handlebars + + @module ember + @submodule ember-routing-handlebars + @requires ember-views + */ + + var Ember = __dependency1__["default"]; + var EmberHandlebars = __dependency2__["default"]; + var Router = __dependency3__["default"]; + + var resolvePaths = __dependency4__.resolvePaths; + var resolveParams = __dependency4__.resolveParams; + + var deprecatedLinkToHelper = __dependency5__.deprecatedLinkToHelper; + var linkToHelper = __dependency5__.linkToHelper; + var LinkView = __dependency5__.LinkView; + var queryParamsHelper = __dependency5__.queryParamsHelper; + + var outletHelper = __dependency6__.outletHelper; + var OutletView = __dependency6__.OutletView; + + var renderHelper = __dependency7__["default"]; + + var ActionHelper = __dependency8__.ActionHelper; + var actionHelper = __dependency8__.actionHelper; + + Router.resolveParams = resolveParams; + Router.resolvePaths = resolvePaths; + + Ember.LinkView = LinkView; + EmberHandlebars.ActionHelper = ActionHelper; + EmberHandlebars.OutletView = OutletView; + + EmberHandlebars.registerHelper('render', renderHelper); + EmberHandlebars.registerHelper('action', actionHelper); + EmberHandlebars.registerHelper('outlet', outletHelper); + EmberHandlebars.registerHelper('link-to', linkToHelper); + EmberHandlebars.registerHelper('linkTo', deprecatedLinkToHelper); + EmberHandlebars.registerHelper('query-params', queryParamsHelper); + + __exports__["default"] = Ember; + }); +enifed("ember-routing-handlebars/helpers/action", + ["ember-metal/core","ember-metal/property_get","ember-metal/array","ember-metal/utils","ember-metal/run_loop","ember-views/system/utils","ember-views/system/action_manager","ember-routing/system/router","ember-handlebars","ember-handlebars/ext","ember-handlebars/helpers/view","ember-routing-handlebars/helpers/shared","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Handlebars, uuid, FEATURES, assert, deprecate + var get = __dependency2__.get; + var forEach = __dependency3__.forEach; + var uuid = __dependency4__.uuid; + var run = __dependency5__["default"]; + + var isSimpleClick = __dependency6__.isSimpleClick; + var ActionManager = __dependency7__["default"]; + var EmberRouter = __dependency8__["default"]; + + var EmberHandlebars = __dependency9__["default"]; + var handlebarsGet = __dependency10__.handlebarsGet; + var viewHelper = __dependency11__.viewHelper; + var resolveParams = __dependency12__.resolveParams; + var resolvePath = __dependency12__.resolvePath; + + /** + @module ember + @submodule ember-routing + */ + + var SafeString = EmberHandlebars.SafeString; + var a_slice = Array.prototype.slice; + + function args(options, actionName) { + var ret = []; + if (actionName) { ret.push(actionName); } + + var types = options.options.types.slice(1); + var data = options.options.data; + + return ret.concat(resolveParams(options.context, options.params, { types: types, data: data })); + } + + var ActionHelper = {}; + + // registeredActions is re-exported for compatibility with older plugins + // that were using this undocumented API. + ActionHelper.registeredActions = ActionManager.registeredActions; + + __exports__.ActionHelper = ActionHelper; + + var keys = ["alt", "shift", "meta", "ctrl"]; + + var POINTER_EVENT_TYPE_REGEX = /^click|mouse|touch/; + + var isAllowedEvent = function(event, allowedKeys) { + if (typeof allowedKeys === "undefined") { + if (POINTER_EVENT_TYPE_REGEX.test(event.type)) { + return isSimpleClick(event); + } else { + allowedKeys = ''; + } + } + + if (allowedKeys.indexOf("any") >= 0) { + return true; + } + + var allowed = true; + + forEach.call(keys, function(key) { + if (event[key + "Key"] && allowedKeys.indexOf(key) === -1) { + allowed = false; + } + }); + + return allowed; + }; + + function isKeyEvent(eventName) { + return ['keyUp', 'keyPress', 'keyDown'].indexOf(eventName) !== -1; + } + + function ignoreKeyEvent(eventName, event, keyCode) { + var any = 'any'; + keyCode = keyCode || any; + return isKeyEvent(eventName) && keyCode !== any && keyCode !== event.which.toString(); + } + + ActionHelper.registerAction = function(actionNameOrPath, options, allowedKeys) { + var actionId = uuid(); + + ActionManager.registeredActions[actionId] = { + eventName: options.eventName, + handler: function handleRegisteredAction(event) { + if (!isAllowedEvent(event, allowedKeys)) { return true; } + + if (options.preventDefault !== false) { + event.preventDefault(); + } + + if (options.bubbles === false) { + event.stopPropagation(); + } + + var target = options.target; + var parameters = options.parameters; + var eventName = options.eventName; + var actionName; + + + if (target.target) { + target = handlebarsGet(target.root, target.target, target.options); + } else { + target = target.root; + } + + if (options.boundProperty) { + actionName = resolveParams(parameters.context, [actionNameOrPath], { types: ['ID'], data: parameters.options.data })[0]; + + if (typeof actionName === 'undefined' || typeof actionName === 'function') { + actionName = actionNameOrPath; + } + } + + if (!actionName) { + actionName = actionNameOrPath; + } + + run(function runRegisteredAction() { + if (target.send) { + target.send.apply(target, args(parameters, actionName)); + } else { + target[actionName].apply(target, args(parameters)); + } + }); + } + }; + + options.view.on('willClearRender', function() { + delete ActionManager.registeredActions[actionId]; + }); + + return actionId; + }; + + /** + + The `{{action}}` helper provides a useful shortcut for registering an HTML + element within a template for a single DOM event and forwarding that + interaction to the template's controller or specified `target` option. + + If the controller does not implement the specified action, the event is sent + to the current route, and it bubbles up the route hierarchy from there. + + For more advanced event handling see [Ember.Component](/api/classes/Ember.Component.html) + + + ### Use + Given the following application Handlebars template on the page + + ```handlebars +
    + click me +
    + ``` + + And application code + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + actions: { + anActionName: function() { + } + } + }); + ``` + + Will result in the following rendered HTML + + ```html +
    +
    + click me +
    +
    + ``` + + Clicking "click me" will trigger the `anActionName` action of the + `App.ApplicationController`. In this case, no additional parameters will be passed. + + If you provide additional parameters to the helper: + + ```handlebars + + ``` + + Those parameters will be passed along as arguments to the JavaScript + function implementing the action. + + ### Event Propagation + + Events triggered through the action helper will automatically have + `.preventDefault()` called on them. You do not need to do so in your event + handlers. If you need to allow event propagation (to handle file inputs for + example) you can supply the `preventDefault=false` option to the `{{action}}` helper: + + ```handlebars +
    + + +
    + ``` + + To disable bubbling, pass `bubbles=false` to the helper: + + ```handlebars + + ``` + + If you need the default handler to trigger you should either register your + own event handler, or use event methods on your view class. See [Ember.View](/api/classes/Ember.View.html) + 'Responding to Browser Events' for more information. + + ### Specifying DOM event type + + By default the `{{action}}` helper registers for DOM `click` events. You can + supply an `on` option to the helper to specify a different DOM event name: + + ```handlebars +
    + click me +
    + ``` + + See `Ember.View` 'Responding to Browser Events' for a list of + acceptable DOM event names. + + ### Specifying whitelisted modifier keys + + By default the `{{action}}` helper will ignore click event with pressed modifier + keys. You can supply an `allowedKeys` option to specify which keys should not be ignored. + + ```handlebars +
    + click me +
    + ``` + + This way the `{{action}}` will fire when clicking with the alt key pressed down. + + Alternatively, supply "any" to the `allowedKeys` option to accept any combination of modifier keys. + + ```handlebars +
    + click me with any key pressed +
    + ``` + + ### Specifying a Target + + There are several possible target objects for `{{action}}` helpers: + + In a typical Ember application, where templates are managed through use of the + `{{outlet}}` helper, actions will bubble to the current controller, then + to the current route, and then up the route hierarchy. + + Alternatively, a `target` option can be provided to the helper to change + which object will receive the method call. This option must be a path + to an object, accessible in the current context: + + ```handlebars + {{! the application template }} +
    + click me +
    + ``` + + ```javascript + App.ApplicationView = Ember.View.extend({ + actions: { + anActionName: function(){} + } + }); + + ``` + + ### Additional Parameters + + You may specify additional parameters to the `{{action}}` helper. These + parameters are passed along as the arguments to the JavaScript function + implementing the action. + + ```handlebars + {{#each person in people}} +
    + click me +
    + {{/each}} + ``` + + Clicking "click me" will trigger the `edit` method on the current controller + with the value of `person` as a parameter. + + @method action + @for Ember.Handlebars.helpers + @param {String} actionName + @param {Object} [context]* + @param {Hash} options + */ + function actionHelper(actionName) { + var options = arguments[arguments.length - 1]; + var contexts = a_slice.call(arguments, 1, -1); + var hash = options.hash; + var controller = options.data.keywords.controller; + + // create a hash to pass along to registerAction + var action = { + eventName: hash.on || "click", + parameters: { + context: this, + options: options, + params: contexts + }, + view: options.data.view, + bubbles: hash.bubbles, + preventDefault: hash.preventDefault, + target: { options: options }, + withKeyCode: hash.withKeyCode, + boundProperty: options.types[0] === "ID" + }; + + if (hash.target) { + action.target.root = this; + action.target.target = hash.target; + } else if (controller) { + action.target.root = controller; + } + + var actionId = ActionHelper.registerAction(actionName, action, hash.allowedKeys); + return new SafeString('data-ember-action="' + actionId + '"'); + } + + __exports__.actionHelper = actionHelper; + }); +enifed("ember-routing-handlebars/helpers/link_to", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/merge","ember-metal/run_loop","ember-metal/computed","ember-runtime/system/lazy_load","ember-runtime/system/string","ember-runtime/system/object","ember-metal/keys","ember-views/system/utils","ember-views/views/component","ember-handlebars","ember-handlebars/helpers/view","ember-routing/system/router","ember-routing-handlebars/helpers/shared","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES, Logger, Handlebars, warn, assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var merge = __dependency4__["default"]; + var run = __dependency5__["default"]; + var computed = __dependency6__.computed; + + var onLoad = __dependency7__.onLoad; + var fmt = __dependency8__.fmt; + var EmberObject = __dependency9__["default"]; + var keys = __dependency10__["default"]; + var isSimpleClick = __dependency11__.isSimpleClick; + var EmberComponent = __dependency12__["default"]; + var EmberHandlebars = __dependency13__["default"]; + var viewHelper = __dependency14__.viewHelper; + var EmberRouter = __dependency15__["default"]; + var resolveParams = __dependency16__.resolveParams; + var resolvePaths = __dependency16__.resolvePaths; + var routeArgs = __dependency16__.routeArgs; + + /** + @module ember + @submodule ember-routing + */ + + var slice = [].slice; + + requireModule('ember-handlebars'); + + var numberOfContextsAcceptedByHandler = function(handler, handlerInfos) { + var req = 0; + for (var i = 0, l = handlerInfos.length; i < l; i++) { + req = req + handlerInfos[i].names.length; + if (handlerInfos[i].handler === handler) + break; + } + + return req; + }; + + var QueryParams = EmberObject.extend({ + values: null + }); + + function getResolvedPaths(options) { + + var types = options.options.types; + var data = options.options.data; + + return resolvePaths(options.context, options.params, { types: types, data: data }); + } + + /** + `Ember.LinkView` renders an element whose `click` event triggers a + transition of the application's instance of `Ember.Router` to + a supplied route by name. + + Instances of `LinkView` will most likely be created through + the `link-to` Handlebars helper, but properties of this class + can be overridden to customize application-wide behavior. + + @class LinkView + @namespace Ember + @extends Ember.View + @see {Handlebars.helpers.link-to} + **/ + var LinkView = Ember.LinkView = EmberComponent.extend({ + tagName: 'a', + + /** + @deprecated Use current-when instead. + @property currentWhen + */ + currentWhen: null, + + /** + Used to determine when this LinkView is active. + + @property currentWhen + */ + 'current-when': null, + + /** + Sets the `title` attribute of the `LinkView`'s HTML element. + + @property title + @default null + **/ + title: null, + + /** + Sets the `rel` attribute of the `LinkView`'s HTML element. + + @property rel + @default null + **/ + rel: null, + + /** + The CSS class to apply to `LinkView`'s element when its `active` + property is `true`. + + @property activeClass + @type String + @default active + **/ + activeClass: 'active', + + /** + The CSS class to apply to `LinkView`'s element when its `loading` + property is `true`. + + @property loadingClass + @type String + @default loading + **/ + loadingClass: 'loading', + + /** + The CSS class to apply to a `LinkView`'s element when its `disabled` + property is `true`. + + @property disabledClass + @type String + @default disabled + **/ + disabledClass: 'disabled', + _isDisabled: false, + + /** + Determines whether the `LinkView` will trigger routing via + the `replaceWith` routing strategy. + + @property replace + @type Boolean + @default false + **/ + replace: false, + + /** + By default the `{{link-to}}` helper will bind to the `href` and + `title` attributes. It's discourage that you override these defaults, + however you can push onto the array if needed. + + @property attributeBindings + @type Array | String + @default ['href', 'title', 'rel'] + **/ + attributeBindings: ['href', 'title', 'rel', 'tabindex'], + + /** + By default the `{{link-to}}` helper will bind to the `active`, `loading`, and + `disabled` classes. It is discouraged to override these directly. + + @property classNameBindings + @type Array + @default ['active', 'loading', 'disabled'] + **/ + classNameBindings: ['active', 'loading', 'disabled'], + + /** + By default the `{{link-to}}` helper responds to the `click` event. You + can override this globally by setting this property to your custom + event name. + + This is particularly useful on mobile when one wants to avoid the 300ms + click delay using some sort of custom `tap` event. + + @property eventName + @type String + @default click + */ + eventName: 'click', + + // this is doc'ed here so it shows up in the events + // section of the API documentation, which is where + // people will likely go looking for it. + /** + Triggers the `LinkView`'s routing behavior. If + `eventName` is changed to a value other than `click` + the routing behavior will trigger on that custom event + instead. + + @event click + **/ + + /** + An overridable method called when LinkView objects are instantiated. + + Example: + + ```javascript + App.MyLinkView = Ember.LinkView.extend({ + init: function() { + this._super(); + Ember.Logger.log('Event is ' + this.get('eventName')); + } + }); + ``` + + NOTE: If you do override `init` for a framework class like `Ember.View` or + `Ember.ArrayController`, be sure to call `this._super()` in your + `init` declaration! If you don't, Ember may not have an opportunity to + do important setup work, and you'll see strange behavior in your + application. + + @method init + */ + init: function() { + this._super.apply(this, arguments); + + + // Map desired event name to invoke function + var eventName = get(this, 'eventName'); + this.on(eventName, this, this._invoke); + }, + + /** + This method is invoked by observers installed during `init` that fire + whenever the params change + + @private + @method _paramsChanged + @since 1.3.0 + */ + _paramsChanged: function() { + this.notifyPropertyChange('resolvedParams'); + }, + + /** + This is called to setup observers that will trigger a rerender. + + @private + @method _setupPathObservers + @since 1.3.0 + **/ + _setupPathObservers: function(){ + var helperParameters = this.parameters; + var linkTextPath = helperParameters.options.linkTextPath; + var paths = getResolvedPaths(helperParameters); + var length = paths.length; + var path, i, normalizedPath; + + if (linkTextPath) { + normalizedPath = getNormalizedPath(linkTextPath, helperParameters); + this.registerObserver(normalizedPath.root, normalizedPath.path, this, this.rerender); + } + + for(i=0; i < length; i++) { + path = paths[i]; + if (null === path) { + // A literal value was provided, not a path, so nothing to observe. + continue; + } + + normalizedPath = getNormalizedPath(path, helperParameters); + this.registerObserver(normalizedPath.root, normalizedPath.path, this, this._paramsChanged); + } + + var queryParamsObject = this.queryParamsObject; + if (queryParamsObject) { + var values = queryParamsObject.values; + + // Install observers for all of the hash options + // provided in the (query-params) subexpression. + for (var k in values) { + if (!values.hasOwnProperty(k)) { continue; } + + if (queryParamsObject.types[k] === 'ID') { + normalizedPath = getNormalizedPath(values[k], helperParameters); + this.registerObserver(normalizedPath.root, normalizedPath.path, this, this._paramsChanged); + } + } + } + }, + + afterRender: function(){ + this._super.apply(this, arguments); + this._setupPathObservers(); + }, + + /** + + Accessed as a classname binding to apply the `LinkView`'s `disabledClass` + CSS `class` to the element when the link is disabled. + + When `true` interactions with the element will not trigger route changes. + @property disabled + */ + disabled: computed(function computeLinkViewDisabled(key, value) { + if (value !== undefined) { this.set('_isDisabled', value); } + + return value ? get(this, 'disabledClass') : false; + }), + + /** + Accessed as a classname binding to apply the `LinkView`'s `activeClass` + CSS `class` to the element when the link is active. + + A `LinkView` is considered active when its `currentWhen` property is `true` + or the application's current route is the route the `LinkView` would trigger + transitions into. + + The `currentWhen` property can match against multiple routes by separating + route names using the ` ` (space) character. + + @property active + **/ + active: computed('loadedParams', function computeLinkViewActive() { + if (get(this, 'loading')) { return false; } + + var router = get(this, 'router'); + var loadedParams = get(this, 'loadedParams'); + var contexts = loadedParams.models; + var currentWhen = this['current-when'] || this.currentWhen; + var isCurrentWhenSpecified = Boolean(currentWhen); + currentWhen = currentWhen || loadedParams.targetRouteName; + + function isActiveForRoute(routeName) { + var handlers = router.router.recognizer.handlersFor(routeName); + var leafName = handlers[handlers.length-1].handler; + var maximumContexts = numberOfContextsAcceptedByHandler(routeName, handlers); + + // NOTE: any ugliness in the calculation of activeness is largely + // due to the fact that we support automatic normalizing of + // `resource` -> `resource.index`, even though there might be + // dynamic segments / query params defined on `resource.index` + // which complicates (and makes somewhat ambiguous) the calculation + // of activeness for links that link to `resource` instead of + // directly to `resource.index`. + + // if we don't have enough contexts revert back to full route name + // this is because the leaf route will use one of the contexts + if (contexts.length > maximumContexts) { + routeName = leafName; + } + + var args = routeArgs(routeName, contexts, null); + var isActive = router.isActive.apply(router, args); + if (!isActive) { return false; } + + var emptyQueryParams = Ember.isEmpty(Ember.keys(loadedParams.queryParams)); + + if (!isCurrentWhenSpecified && !emptyQueryParams && isActive) { + var visibleQueryParams = {}; + merge(visibleQueryParams, loadedParams.queryParams); + router._prepareQueryParams(loadedParams.targetRouteName, loadedParams.models, visibleQueryParams); + isActive = shallowEqual(visibleQueryParams, router.router.state.queryParams); + } + + return isActive; + } + + + currentWhen = currentWhen.split(' '); + for (var i = 0, len = currentWhen.length; i < len; i++) { + if (isActiveForRoute(currentWhen[i])) { + return get(this, 'activeClass'); + } + } + }), + + /** + Accessed as a classname binding to apply the `LinkView`'s `loadingClass` + CSS `class` to the element when the link is loading. + + A `LinkView` is considered loading when it has at least one + parameter whose value is currently null or undefined. During + this time, clicking the link will perform no transition and + emit a warning that the link is still in a loading state. + + @property loading + **/ + loading: computed('loadedParams', function computeLinkViewLoading() { + if (!get(this, 'loadedParams')) { return get(this, 'loadingClass'); } + }), + + /** + Returns the application's main router from the container. + + @private + @property router + **/ + router: computed(function() { + var controller = get(this, 'controller'); + if (controller && controller.container) { + return controller.container.lookup('router:main'); + } + }), + + /** + Event handler that invokes the link, activating the associated route. + + @private + @method _invoke + @param {Event} event + */ + _invoke: function(event) { + if (!isSimpleClick(event)) { return true; } + + if (this.preventDefault !== false) { + + var targetAttribute = get(this, 'target'); + if (!targetAttribute || targetAttribute === '_self') { + event.preventDefault(); + } + } + + if (this.bubbles === false) { event.stopPropagation(); } + + if (get(this, '_isDisabled')) { return false; } + + if (get(this, 'loading')) { + Ember.Logger.warn("This link-to is in an inactive loading state because at least one of its parameters presently has a null/undefined value, or the provided route name is invalid."); + return false; + } + + + var targetAttribute2 = get(this, 'target'); + if (targetAttribute2 && targetAttribute2 !== '_self') { + return false; + } + + + var router = get(this, 'router'); + var loadedParams = get(this, 'loadedParams'); + + var transition = router._doTransition(loadedParams.targetRouteName, loadedParams.models, loadedParams.queryParams); + if (get(this, 'replace')) { + transition.method('replace'); + } + + // Schedule eager URL update, but after we've given the transition + // a chance to synchronously redirect. + // We need to always generate the URL instead of using the href because + // the href will include any rootURL set, but the router expects a URL + // without it! Note that we don't use the first level router because it + // calls location.formatURL(), which also would add the rootURL! + var args = routeArgs(loadedParams.targetRouteName, loadedParams.models, transition.state.queryParams); + var url = router.router.generate.apply(router.router, args); + + run.scheduleOnce('routerTransitions', this, this._eagerUpdateUrl, transition, url); + }, + + /** + @private + @method _eagerUpdateUrl + @param transition + @param href + */ + _eagerUpdateUrl: function(transition, href) { + if (!transition.isActive || !transition.urlMethod) { + // transition was aborted, already ran to completion, + // or it has a null url-updated method. + return; + } + + if (href.indexOf('#') === 0) { + href = href.slice(1); + } + + // Re-use the routerjs hooks set up by the Ember router. + var routerjs = get(this, 'router.router'); + if (transition.urlMethod === 'update') { + routerjs.updateURL(href); + } else if (transition.urlMethod === 'replace') { + routerjs.replaceURL(href); + } + + // Prevent later update url refire. + transition.method(null); + }, + + /** + Computed property that returns an array of the + resolved parameters passed to the `link-to` helper, + e.g.: + + ```hbs + {{link-to a b '123' c}} + ``` + + will generate a `resolvedParams` of: + + ```js + [aObject, bObject, '123', cObject] + ``` + + @private + @property + @return {Array} + */ + resolvedParams: computed('router.url', function() { + var parameters = this.parameters; + var options = parameters.options; + var types = options.types; + var data = options.data; + var targetRouteName, models; + var onlyQueryParamsSupplied = (parameters.params.length === 0); + + if (onlyQueryParamsSupplied) { + var appController = this.container.lookup('controller:application'); + targetRouteName = get(appController, 'currentRouteName'); + models = []; + } else { + models = resolveParams(parameters.context, parameters.params, { types: types, data: data }); + targetRouteName = models.shift(); + } + + var suppliedQueryParams = getResolvedQueryParams(this, targetRouteName); + + return { + targetRouteName: targetRouteName, + models: models, + queryParams: suppliedQueryParams + }; + }), + + /** + Computed property that returns the current route name, + dynamic segments, and query params. Returns falsy if + for null/undefined params to indicate that the link view + is still in a loading state. + + @private + @property + @return {Array} An array with the route name and any dynamic segments + **/ + loadedParams: computed('resolvedParams', function computeLinkViewRouteArgs() { + var router = get(this, 'router'); + if (!router) { return; } + + var resolvedParams = get(this, 'resolvedParams'); + var namedRoute = resolvedParams.targetRouteName; + + if (!namedRoute) { return; } + + + if (!paramsAreLoaded(resolvedParams.models)) { return; } + + return resolvedParams; + }), + + queryParamsObject: null, + + /** + Sets the element's `href` attribute to the url for + the `LinkView`'s targeted route. + + If the `LinkView`'s `tagName` is changed to a value other + than `a`, this property will be ignored. + + @property href + **/ + href: computed('loadedParams', function computeLinkViewHref() { + if (get(this, 'tagName') !== 'a') { return; } + + var router = get(this, 'router'); + var loadedParams = get(this, 'loadedParams'); + + if (!loadedParams) { + return get(this, 'loadingHref'); + } + + var visibleQueryParams = {}; + merge(visibleQueryParams, loadedParams.queryParams); + router._prepareQueryParams(loadedParams.targetRouteName, loadedParams.models, visibleQueryParams); + + var args = routeArgs(loadedParams.targetRouteName, loadedParams.models, visibleQueryParams); + var result = router.generate.apply(router, args); + return result; + }), + + /** + The default href value to use while a link-to is loading. + Only applies when tagName is 'a' + + @property loadingHref + @type String + @default # + */ + loadingHref: '#' + }); + + LinkView.toString = function() { return "LinkView"; }; + + + LinkView.reopen({ + attributeBindings: ['target'], + + /** + Sets the `target` attribute of the `LinkView`'s anchor element. + + @property target + @default null + **/ + target: null + }); + + + /** + The `{{link-to}}` helper renders a link to the supplied + `routeName` passing an optionally supplied model to the + route as its `model` context of the route. The block + for `{{link-to}}` becomes the innerHTML of the rendered + element: + + ```handlebars + {{#link-to 'photoGallery'}} + Great Hamster Photos + {{/link-to}} + ``` + + ```html + + Great Hamster Photos + + ``` + + ### Supplying a tagName + By default `{{link-to}}` renders an `` element. This can + be overridden for a single use of `{{link-to}}` by supplying + a `tagName` option: + + ```handlebars + {{#link-to 'photoGallery' tagName="li"}} + Great Hamster Photos + {{/link-to}} + ``` + + ```html +
  • + Great Hamster Photos +
  • + ``` + + To override this option for your entire application, see + "Overriding Application-wide Defaults". + + ### Disabling the `link-to` helper + By default `{{link-to}}` is enabled. + any passed value to `disabled` helper property will disable the `link-to` helper. + + static use: the `disabled` option: + + ```handlebars + {{#link-to 'photoGallery' disabled=true}} + Great Hamster Photos + {{/link-to}} + ``` + + dynamic use: the `disabledWhen` option: + + ```handlebars + {{#link-to 'photoGallery' disabledWhen=controller.someProperty}} + Great Hamster Photos + {{/link-to}} + ``` + + any passed value to `disabled` will disable it except `undefined`. + to ensure that only `true` disable the `link-to` helper you can + override the global behaviour of `Ember.LinkView`. + + ```javascript + Ember.LinkView.reopen({ + disabled: Ember.computed(function(key, value) { + if (value !== undefined) { + this.set('_isDisabled', value === true); + } + return value === true ? get(this, 'disabledClass') : false; + }) + }); + ``` + + see "Overriding Application-wide Defaults" for more. + + ### Handling `href` + `{{link-to}}` will use your application's Router to + fill the element's `href` property with a url that + matches the path to the supplied `routeName` for your + routers's configured `Location` scheme, which defaults + to Ember.HashLocation. + + ### Handling current route + `{{link-to}}` will apply a CSS class name of 'active' + when the application's current route matches + the supplied routeName. For example, if the application's + current route is 'photoGallery.recent' the following + use of `{{link-to}}`: + + ```handlebars + {{#link-to 'photoGallery.recent'}} + Great Hamster Photos from the last week + {{/link-to}} + ``` + + will result in + + ```html +
    + Great Hamster Photos + + ``` + + The CSS class name used for active classes can be customized + for a single use of `{{link-to}}` by passing an `activeClass` + option: + + ```handlebars + {{#link-to 'photoGallery.recent' activeClass="current-url"}} + Great Hamster Photos from the last week + {{/link-to}} + ``` + + ```html + + Great Hamster Photos + + ``` + + To override this option for your entire application, see + "Overriding Application-wide Defaults". + + ### Supplying a model + An optional model argument can be used for routes whose + paths contain dynamic segments. This argument will become + the model context of the linked route: + + ```javascript + App.Router.map(function() { + this.resource("photoGallery", {path: "hamster-photos/:photo_id"}); + }); + ``` + + ```handlebars + {{#link-to 'photoGallery' aPhoto}} + {{aPhoto.title}} + {{/link-to}} + ``` + + ```html + + Tomster + + ``` + + ### Supplying multiple models + For deep-linking to route paths that contain multiple + dynamic segments, multiple model arguments can be used. + As the router transitions through the route path, each + supplied model argument will become the context for the + route with the dynamic segments: + + ```javascript + App.Router.map(function() { + this.resource("photoGallery", {path: "hamster-photos/:photo_id"}, function() { + this.route("comment", {path: "comments/:comment_id"}); + }); + }); + ``` + This argument will become the model context of the linked route: + + ```handlebars + {{#link-to 'photoGallery.comment' aPhoto comment}} + {{comment.body}} + {{/link-to}} + ``` + + ```html + + A+++ would snuggle again. + + ``` + + ### Supplying an explicit dynamic segment value + If you don't have a model object available to pass to `{{link-to}}`, + an optional string or integer argument can be passed for routes whose + paths contain dynamic segments. This argument will become the value + of the dynamic segment: + + ```javascript + App.Router.map(function() { + this.resource("photoGallery", {path: "hamster-photos/:photo_id"}); + }); + ``` + + ```handlebars + {{#link-to 'photoGallery' aPhotoId}} + {{aPhoto.title}} + {{/link-to}} + ``` + + ```html + + Tomster + + ``` + + When transitioning into the linked route, the `model` hook will + be triggered with parameters including this passed identifier. + + ### Allowing Default Action + + By default the `{{link-to}}` helper prevents the default browser action + by calling `preventDefault()` as this sort of action bubbling is normally + handled internally and we do not want to take the browser to a new URL (for + example). + + If you need to override this behavior specify `preventDefault=false` in + your template: + + ```handlebars + {{#link-to 'photoGallery' aPhotoId preventDefault=false}} + {{aPhotoId.title}} + {{/link-to}} + ``` + + ### Overriding attributes + You can override any given property of the Ember.LinkView + that is generated by the `{{link-to}}` helper by passing + key/value pairs, like so: + + ```handlebars + {{#link-to aPhoto tagName='li' title='Following this link will change your life' classNames='pic sweet'}} + Uh-mazing! + {{/link-to}} + ``` + + See [Ember.LinkView](/api/classes/Ember.LinkView.html) for a + complete list of overrideable properties. Be sure to also + check out inherited properties of `LinkView`. + + ### Overriding Application-wide Defaults + ``{{link-to}}`` creates an instance of Ember.LinkView + for rendering. To override options for your entire + application, reopen Ember.LinkView and supply the + desired values: + + ``` javascript + Ember.LinkView.reopen({ + activeClass: "is-active", + tagName: 'li' + }) + ``` + + It is also possible to override the default event in + this manner: + + ``` javascript + Ember.LinkView.reopen({ + eventName: 'customEventName' + }); + ``` + + @method link-to + @for Ember.Handlebars.helpers + @param {String} routeName + @param {Object} [context]* + @param [options] {Object} Handlebars key/value pairs of options, you can override any property of Ember.LinkView + @return {String} HTML string + @see {Ember.LinkView} + */ + function linkToHelper(name) { + var options = slice.call(arguments, -1)[0]; + var params = slice.call(arguments, 0, -1); + var hash = options.hash; + + + if (params[params.length - 1] instanceof QueryParams) { + hash.queryParamsObject = params.pop(); + } + + hash.disabledBinding = hash.disabledWhen; + + if (!options.fn) { + var linkTitle = params.shift(); + var linkType = options.types.shift(); + var context = this; + if (linkType === 'ID') { + options.linkTextPath = linkTitle; + options.fn = function() { + return EmberHandlebars.getEscaped(context, linkTitle, options); + }; + } else { + options.fn = function() { + return linkTitle; + }; + } + } + + hash.parameters = { + context: this, + options: options, + params: params + }; + + options.helperName = options.helperName || 'link-to'; + + return viewHelper.call(this, LinkView, options); + } + + /** + @method query-params + @for Ember.Handlebars.helpers + @param {Object} hash takes a hash of query parameters + @return {String} HTML string + */ + function queryParamsHelper(options) { + + return QueryParams.create({ + values: options.hash, + types: options.hashTypes + }); + } + + __exports__.queryParamsHelper = queryParamsHelper;/** + See [link-to](/api/classes/Ember.Handlebars.helpers.html#method_link-to) + + @method linkTo + @for Ember.Handlebars.helpers + @deprecated + @param {String} routeName + @param {Object} [context]* + @return {String} HTML string + */ + function deprecatedLinkToHelper() { + return linkToHelper.apply(this, arguments); + } + + function getResolvedQueryParams(linkView, targetRouteName) { + var helperParameters = linkView.parameters; + var queryParamsObject = linkView.queryParamsObject; + var resolvedQueryParams = {}; + + if (!queryParamsObject) { return resolvedQueryParams; } + var rawParams = queryParamsObject.values; + + for (var key in rawParams) { + if (!rawParams.hasOwnProperty(key)) { continue; } + + var value = rawParams[key]; + var type = queryParamsObject.types[key]; + + if (type === 'ID') { + var normalizedPath = getNormalizedPath(value, helperParameters); + value = EmberHandlebars.get(normalizedPath.root, normalizedPath.path, helperParameters.options); + } + resolvedQueryParams[key] = value; + } + return resolvedQueryParams; + } + + function getNormalizedPath(path, helperParameters) { + return EmberHandlebars.normalizePath(helperParameters.context, path, helperParameters.options.data); + } + + function paramsAreLoaded(params) { + for (var i = 0, len = params.length; i < len; ++i) { + var param = params[i]; + if (param === null || typeof param === 'undefined') { + return false; + } + } + return true; + } + + function shallowEqual(a, b) { + var k; + for (k in a) { + if (a.hasOwnProperty(k) && a[k] !== b[k]) { return false; } + } + for (k in b) { + if (b.hasOwnProperty(k) && a[k] !== b[k]) { return false; } + } + return true; + } + + __exports__.LinkView = LinkView; + __exports__.deprecatedLinkToHelper = deprecatedLinkToHelper; + __exports__.linkToHelper = linkToHelper; + }); +enifed("ember-routing-handlebars/helpers/outlet", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/lazy_load","ember-views/views/container_view","ember-handlebars/views/metamorph_view","ember-handlebars/helpers/view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var onLoad = __dependency4__.onLoad; + var ContainerView = __dependency5__["default"]; + var _Metamorph = __dependency6__._Metamorph; + var viewHelper = __dependency7__.viewHelper; + + /** + @module ember + @submodule ember-routing + */ + + /** + @module ember + @submodule ember-routing + */ + + var OutletView = ContainerView.extend(_Metamorph); + __exports__.OutletView = OutletView; + /** + The `outlet` helper is a placeholder that the router will fill in with + the appropriate template based on the current state of the application. + + ``` handlebars + {{outlet}} + ``` + + By default, a template based on Ember's naming conventions will be rendered + into the `outlet` (e.g. `App.PostsRoute` will render the `posts` template). + + You can render a different template by using the `render()` method in the + route's `renderTemplate` hook. The following will render the `favoritePost` + template into the `outlet`. + + ``` javascript + App.PostsRoute = Ember.Route.extend({ + renderTemplate: function() { + this.render('favoritePost'); + } + }); + ``` + + You can create custom named outlets for more control. + + ``` handlebars + {{outlet 'favoritePost'}} + {{outlet 'posts'}} + ``` + + Then you can define what template is rendered into each outlet in your + route. + + + ``` javascript + App.PostsRoute = Ember.Route.extend({ + renderTemplate: function() { + this.render('favoritePost', { outlet: 'favoritePost' }); + this.render('posts', { outlet: 'posts' }); + } + }); + ``` + + You can specify the view that the outlet uses to contain and manage the + templates rendered into it. + + ``` handlebars + {{outlet view='sectionContainer'}} + ``` + + ``` javascript + App.SectionContainer = Ember.ContainerView.extend({ + tagName: 'section', + classNames: ['special'] + }); + ``` + + @method outlet + @for Ember.Handlebars.helpers + @param {String} property the property on the controller + that holds the view for this outlet + @return {String} HTML string + */ + function outletHelper(property, options) { + var outletSource; + var container; + var viewName; + var viewClass; + var viewFullName; + + if (property && property.data && property.data.isRenderData) { + options = property; + property = 'main'; + } + + container = options.data.view.container; + + outletSource = options.data.view; + while (!outletSource.get('template.isTop')) { + outletSource = outletSource.get('_parentView'); + } + + // provide controller override + viewName = options.hash.view; + + if (viewName) { + viewFullName = 'view:' + viewName; + } + + viewClass = viewName ? container.lookupFactory(viewFullName) : options.hash.viewClass || OutletView; + + options.data.view.set('outletSource', outletSource); + options.hash.currentViewBinding = '_view.outletSource._outlets.' + property; + + options.helperName = options.helperName || 'outlet'; + + return viewHelper.call(this, viewClass, options); + } + + __exports__.outletHelper = outletHelper; + }); +enifed("ember-routing-handlebars/helpers/render", + ["ember-metal/core","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/string","ember-routing/system/generate_controller","ember-handlebars/ext","ember-handlebars/helpers/view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // assert, deprecate + var EmberError = __dependency2__["default"]; + var get = __dependency3__.get; + var set = __dependency4__.set; + var camelize = __dependency5__.camelize; + var generateControllerFactory = __dependency6__.generateControllerFactory; + var generateController = __dependency6__["default"]; + var handlebarsGet = __dependency7__.handlebarsGet; + var ViewHelper = __dependency8__.ViewHelper; + + + /** + @module ember + @submodule ember-routing + */ + + /** + Calling ``{{render}}`` from within a template will insert another + template that matches the provided name. The inserted template will + access its properties on its own controller (rather than the controller + of the parent template). + + If a view class with the same name exists, the view class also will be used. + + Note: A given controller may only be used *once* in your app in this manner. + A singleton instance of the controller will be created for you. + + Example: + + ```javascript + App.NavigationController = Ember.Controller.extend({ + who: "world" + }); + ``` + + ```handlebars + + Hello, {{who}}. + ``` + + ```handelbars + +

    My great app

    + {{render "navigation"}} + ``` + + ```html +

    My great app

    +
    + Hello, world. +
    + ``` + + Optionally you may provide a second argument: a property path + that will be bound to the `model` property of the controller. + + If a `model` property path is specified, then a new instance of the + controller will be created and `{{render}}` can be used multiple times + with the same name. + + For example if you had this `author` template. + + ```handlebars +
    + Written by {{firstName}} {{lastName}}. + Total Posts: {{postCount}} +
    + ``` + + You could render it inside the `post` template using the `render` helper. + + ```handlebars +
    +

    {{title}}

    +
    {{body}}
    + {{render "author" author}} +
    + ``` + + @method render + @for Ember.Handlebars.helpers + @param {String} name + @param {Object?} contextString + @param {Hash} options + @return {String} HTML string + */ + __exports__["default"] = function renderHelper(name, contextString, options) { + var length = arguments.length; + var contextProvided = length === 3; + var container, router, controller, view, context, lookupOptions; + + container = (options || contextString).data.keywords.controller.container; + router = container.lookup('router:main'); + + if (length === 2) { + // use the singleton controller + options = contextString; + contextString = undefined; + } else if (length === 3) { + // create a new controller + context = handlebarsGet(options.contexts[1], contextString, options); + } else { + throw new EmberError("You must pass a templateName to render"); + } + + + // # legacy namespace + name = name.replace(/\//g, '.'); + // \ legacy slash as namespace support + + + view = container.lookup('view:' + name) || container.lookup('view:default'); + + // provide controller override + var controllerName = options.hash.controller || name; + var controllerFullName = 'controller:' + controllerName; + + if (options.hash.controller) { + } + + var parentController = options.data.keywords.controller; + + // choose name + if (length > 2) { + var factory = container.lookupFactory(controllerFullName) || + generateControllerFactory(container, controllerName, context); + + controller = factory.create({ + model: context, + parentController: parentController, + target: parentController + }); + + view.one('willDestroyElement', function() { + controller.destroy(); + }); + } else { + controller = container.lookup(controllerFullName) || + generateController(container, controllerName); + + controller.setProperties({ + target: parentController, + parentController: parentController + }); + } + + var root = options.contexts[1]; + + if (root) { + view.registerObserver(root, contextString, function() { + controller.set('model', handlebarsGet(root, contextString, options)); + }); + } + + options.hash.viewName = camelize(name); + + var templateName = 'template:' + name; + options.hash.template = container.lookup(templateName); + + options.hash.controller = controller; + + if (router && !context) { + router._connectActiveView(name, view); + } + + options.helperName = options.helperName || ('render "' + name + '"'); + + ViewHelper.instanceHelper(this, view, options); + } + }); +enifed("ember-routing-handlebars/helpers/shared", + ["ember-metal/property_get","ember-metal/array","ember-runtime/mixins/controller","ember-handlebars/ext","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var map = __dependency2__.map; + var ControllerMixin = __dependency3__["default"]; + var handlebarsResolve = __dependency4__.resolveParams; + var handlebarsGet = __dependency4__.handlebarsGet; + var typeOf = __dependency5__.typeOf; + var get = __dependency1__.get; + + function routeArgs(targetRouteName, models, queryParams) { + var args = []; + if (typeOf(targetRouteName) === 'string') { + args.push('' + targetRouteName); + } + args.push.apply(args, models); + args.push({ queryParams: queryParams }); + return args; + } + + __exports__.routeArgs = routeArgs;function getActiveTargetName(router) { + var handlerInfos = router.activeTransition ? + router.activeTransition.state.handlerInfos : + router.state.handlerInfos; + return handlerInfos[handlerInfos.length - 1].name; + } + + __exports__.getActiveTargetName = getActiveTargetName;function resolveParams(context, params, options) { + return map.call(resolvePaths(context, params, options), function(path, i) { + if (null === path) { + // Param was string/number, not a path, so just return raw string/number. + return params[i]; + } else { + return handlebarsGet(context, path, options); + } + }); + } + + __exports__.resolveParams = resolveParams;function stashParamNames(router, handlerInfos) { + if (handlerInfos._namesStashed) { return; } + + // This helper exists because router.js/route-recognizer.js awkwardly + // keeps separate a handlerInfo's list of parameter names depending + // on whether a URL transition or named transition is happening. + // Hopefully we can remove this in the future. + var targetRouteName = handlerInfos[handlerInfos.length-1].name; + var recogHandlers = router.router.recognizer.handlersFor(targetRouteName); + var dynamicParent = null; + + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var handlerInfo = handlerInfos[i]; + var names = recogHandlers[i].names; + + if (names.length) { + dynamicParent = handlerInfo; + } + + handlerInfo._names = names; + + var route = handlerInfo.handler; + route._stashNames(handlerInfo, dynamicParent); + } + + handlerInfos._namesStashed = true; + } + + __exports__.stashParamNames = stashParamNames;function resolvePaths(context, params, options) { + var resolved = handlebarsResolve(context, params, options); + var types = options.types; + + return map.call(resolved, function(object, i) { + if (types[i] === 'ID') { + return unwrap(object, params[i]); + } else { + return null; + } + }); + + function unwrap(object, path) { + if (path === 'controller') { return path; } + + if (ControllerMixin.detect(object)) { + return unwrap(get(object, 'model'), path ? path + '.model' : 'model'); + } else { + return path; + } + } + } + + __exports__.resolvePaths = resolvePaths; + }); +enifed("ember-routing", + ["ember-handlebars","ember-metal/core","ember-routing/ext/run_loop","ember-routing/ext/controller","ember-routing/ext/view","ember-routing/location/api","ember-routing/location/none_location","ember-routing/location/hash_location","ember-routing/location/history_location","ember-routing/location/auto_location","ember-routing/system/generate_controller","ember-routing/system/controller_for","ember-routing/system/dsl","ember-routing/system/router","ember-routing/system/route","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __exports__) { + "use strict"; + /** + Ember Routing + + @module ember + @submodule ember-routing + @requires ember-views + */ + + var EmberHandlebars = __dependency1__["default"]; + var Ember = __dependency2__["default"]; + + // ES6TODO: Cleanup modules with side-effects below + + var EmberLocation = __dependency6__["default"]; + var NoneLocation = __dependency7__["default"]; + var HashLocation = __dependency8__["default"]; + var HistoryLocation = __dependency9__["default"]; + var AutoLocation = __dependency10__["default"]; + + var generateControllerFactory = __dependency11__.generateControllerFactory; + var generateController = __dependency11__["default"]; + var controllerFor = __dependency12__["default"]; + var RouterDSL = __dependency13__["default"]; + var Router = __dependency14__["default"]; + var Route = __dependency15__["default"]; + + Ember.Location = EmberLocation; + Ember.AutoLocation = AutoLocation; + Ember.HashLocation = HashLocation; + Ember.HistoryLocation = HistoryLocation; + Ember.NoneLocation = NoneLocation; + + Ember.controllerFor = controllerFor; + Ember.generateControllerFactory = generateControllerFactory; + Ember.generateController = generateController; + Ember.RouterDSL = RouterDSL; + Ember.Router = Router; + Ember.Route = Route; + + __exports__["default"] = Ember; + }); +enifed("ember-routing/ext/controller", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/computed","ember-metal/utils","ember-metal/merge","ember-metal/enumerable_utils","ember-runtime/mixins/controller","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES, deprecate + var get = __dependency2__.get; + var set = __dependency3__.set; + var computed = __dependency4__.computed; + var typeOf = __dependency5__.typeOf; + var meta = __dependency5__.meta; + var merge = __dependency6__["default"]; + var map = __dependency7__.map; + + var ControllerMixin = __dependency8__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + ControllerMixin.reopen({ + concatenatedProperties: ['queryParams', '_pCacheMeta'], + + init: function() { + this._super.apply(this, arguments); + listenForQueryParamChanges(this); + }, + + /** + @property queryParams + @public + */ + queryParams: null, + + /** + @property _qpDelegate + @private + */ + _qpDelegate: null, + + /** + @property _normalizedQueryParams + @private + */ + _normalizedQueryParams: computed(function() { + var m = meta(this); + if (m.proto !== this) { + return get(m.proto, '_normalizedQueryParams'); + } + + var queryParams = get(this, 'queryParams'); + if (queryParams._qpMap) { + return queryParams._qpMap; + } + + var qpMap = queryParams._qpMap = {}; + + for (var i = 0, len = queryParams.length; i < len; ++i) { + accumulateQueryParamDescriptors(queryParams[i], qpMap); + } + + return qpMap; + }), + + /** + @property _cacheMeta + @private + */ + _cacheMeta: computed(function() { + var m = meta(this); + if (m.proto !== this) { + return get(m.proto, '_cacheMeta'); + } + + var cacheMeta = {}; + var qpMap = get(this, '_normalizedQueryParams'); + for (var prop in qpMap) { + if (!qpMap.hasOwnProperty(prop)) { continue; } + + var qp = qpMap[prop]; + var scope = qp.scope; + var parts; + + if (scope === 'controller') { + parts = []; + } + + cacheMeta[prop] = { + parts: parts, // provided by route if 'model' scope + values: null, // provided by route + scope: scope, + prefix: "", + def: get(this, prop) + }; + } + + return cacheMeta; + }), + + /** + @method _updateCacheParams + @private + */ + _updateCacheParams: function(params) { + var cacheMeta = get(this, '_cacheMeta'); + for (var prop in cacheMeta) { + if (!cacheMeta.hasOwnProperty(prop)) { continue; } + var propMeta = cacheMeta[prop]; + propMeta.values = params; + + var cacheKey = this._calculateCacheKey(propMeta.prefix, propMeta.parts, propMeta.values); + var cache = this._bucketCache; + + if (cache) { + var value = cache.lookup(cacheKey, prop, propMeta.def); + set(this, prop, value); + } + } + }, + + /** + @method _qpChanged + @private + */ + _qpChanged: function(controller, _prop) { + var prop = _prop.substr(0, _prop.length-3); + var cacheMeta = get(controller, '_cacheMeta'); + var propCache = cacheMeta[prop]; + var cacheKey = controller._calculateCacheKey(propCache.prefix || "", propCache.parts, propCache.values); + var value = get(controller, prop); + + // 1. Update model-dep cache + var cache = this._bucketCache; + if (cache) { + controller._bucketCache.stash(cacheKey, prop, value); + } + + // 2. Notify a delegate (e.g. to fire a qp transition) + var delegate = controller._qpDelegate; + if (delegate) { + delegate(controller, prop); + } + }, + + /** + @method _calculateCacheKey + @private + */ + _calculateCacheKey: function(prefix, _parts, values) { + var parts = _parts || [], suffixes = ""; + for (var i = 0, len = parts.length; i < len; ++i) { + var part = parts[i]; + var value = get(values, part); + suffixes += "::" + part + ":" + value; + } + return prefix + suffixes.replace(ALL_PERIODS_REGEX, '-'); + }, + + /** + Transition the application into another route. The route may + be either a single route or route path: + + ```javascript + aController.transitionToRoute('blogPosts'); + aController.transitionToRoute('blogPosts.recentEntries'); + ``` + + Optionally supply a model for the route in question. The model + will be serialized into the URL using the `serialize` hook of + the route: + + ```javascript + aController.transitionToRoute('blogPost', aPost); + ``` + + If a literal is passed (such as a number or a string), it will + be treated as an identifier instead. In this case, the `model` + hook of the route will be triggered: + + ```javascript + aController.transitionToRoute('blogPost', 1); + ``` + + Multiple models will be applied last to first recursively up the + resource tree. + + ```javascript + App.Router.map(function() { + this.resource('blogPost', {path:':blogPostId'}, function(){ + this.resource('blogComment', {path: ':blogCommentId'}); + }); + }); + + aController.transitionToRoute('blogComment', aPost, aComment); + aController.transitionToRoute('blogComment', 1, 13); + ``` + + It is also possible to pass a URL (a string that starts with a + `/`). This is intended for testing and debugging purposes and + should rarely be used in production code. + + ```javascript + aController.transitionToRoute('/'); + aController.transitionToRoute('/blog/post/1/comment/13'); + ``` + + See also [replaceRoute](/api/classes/Ember.ControllerMixin.html#method_replaceRoute). + + @param {String} name the name of the route or a URL + @param {...Object} models the model(s) or identifier(s) to be used + while transitioning to the route. + @for Ember.ControllerMixin + @method transitionToRoute + */ + transitionToRoute: function() { + // target may be either another controller or a router + var target = get(this, 'target'); + var method = target.transitionToRoute || target.transitionTo; + return method.apply(target, arguments); + }, + + /** + @deprecated + @for Ember.ControllerMixin + @method transitionTo + */ + transitionTo: function() { + return this.transitionToRoute.apply(this, arguments); + }, + + /** + Transition into another route while replacing the current URL, if possible. + This will replace the current history entry instead of adding a new one. + Beside that, it is identical to `transitionToRoute` in all other respects. + + ```javascript + aController.replaceRoute('blogPosts'); + aController.replaceRoute('blogPosts.recentEntries'); + ``` + + Optionally supply a model for the route in question. The model + will be serialized into the URL using the `serialize` hook of + the route: + + ```javascript + aController.replaceRoute('blogPost', aPost); + ``` + + If a literal is passed (such as a number or a string), it will + be treated as an identifier instead. In this case, the `model` + hook of the route will be triggered: + + ```javascript + aController.replaceRoute('blogPost', 1); + ``` + + Multiple models will be applied last to first recursively up the + resource tree. + + ```javascript + App.Router.map(function() { + this.resource('blogPost', {path:':blogPostId'}, function(){ + this.resource('blogComment', {path: ':blogCommentId'}); + }); + }); + + aController.replaceRoute('blogComment', aPost, aComment); + aController.replaceRoute('blogComment', 1, 13); + ``` + + It is also possible to pass a URL (a string that starts with a + `/`). This is intended for testing and debugging purposes and + should rarely be used in production code. + + ```javascript + aController.replaceRoute('/'); + aController.replaceRoute('/blog/post/1/comment/13'); + ``` + + @param {String} name the name of the route or a URL + @param {...Object} models the model(s) or identifier(s) to be used + while transitioning to the route. + @for Ember.ControllerMixin + @method replaceRoute + */ + replaceRoute: function() { + // target may be either another controller or a router + var target = get(this, 'target'); + var method = target.replaceRoute || target.replaceWith; + return method.apply(target, arguments); + }, + + /** + @deprecated + @for Ember.ControllerMixin + @method replaceWith + */ + replaceWith: function() { + return this.replaceRoute.apply(this, arguments); + } + }); + + var ALL_PERIODS_REGEX = /\./g; + + function accumulateQueryParamDescriptors(_desc, accum) { + var desc = _desc, tmp; + if (typeOf(desc) === 'string') { + tmp = {}; + tmp[desc] = { as: null }; + desc = tmp; + } + + for (var key in desc) { + if (!desc.hasOwnProperty(key)) { return; } + + var singleDesc = desc[key]; + if (typeOf(singleDesc) === 'string') { + singleDesc = { as: singleDesc }; + } + + tmp = accum[key] || { as: null, scope: 'model' }; + merge(tmp, singleDesc); + + accum[key] = tmp; + } + } + + function listenForQueryParamChanges(controller) { + var qpMap = get(controller, '_normalizedQueryParams'); + for (var prop in qpMap) { + if (!qpMap.hasOwnProperty(prop)) { continue; } + controller.addObserver(prop + '.[]', controller, controller._qpChanged); + } + } + + + __exports__["default"] = ControllerMixin; + }); +enifed("ember-routing/ext/run_loop", + ["ember-metal/run_loop"], + function(__dependency1__) { + "use strict"; + var run = __dependency1__["default"]; + + /** + @module ember + @submodule ember-views + */ + + // Add a new named queue after the 'actions' queue (where RSVP promises + // resolve), which is used in router transitions to prevent unnecessary + // loading state entry if all context promises resolve on the + // 'actions' queue first. + + var queues = run.queues; + run._addQueue('routerTransitions', 'actions'); + }); +enifed("ember-routing/ext/view", + ["ember-metal/property_get","ember-metal/property_set","ember-metal/run_loop","ember-views/views/view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var set = __dependency2__.set; + var run = __dependency3__["default"]; + var EmberView = __dependency4__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + EmberView.reopen({ + + /** + Sets the private `_outlets` object on the view. + + @method init + */ + init: function() { + set(this, '_outlets', {}); + this._super(); + }, + + /** + Manually fill any of a view's `{{outlet}}` areas with the + supplied view. + + Example + + ```javascript + var MyView = Ember.View.extend({ + template: Ember.Handlebars.compile('Child view: {{outlet "main"}} ') + }); + var myView = MyView.create(); + myView.appendTo('body'); + // The html for myView now looks like: + //
    Child view:
    + + var FooView = Ember.View.extend({ + template: Ember.Handlebars.compile('

    Foo

    ') + }); + var fooView = FooView.create(); + myView.connectOutlet('main', fooView); + // The html for myView now looks like: + //
    Child view: + //

    Foo

    + //
    + ``` + @method connectOutlet + @param {String} outletName A unique name for the outlet + @param {Object} view An Ember.View + */ + connectOutlet: function(outletName, view) { + if (this._pendingDisconnections) { + delete this._pendingDisconnections[outletName]; + } + + if (this._hasEquivalentView(outletName, view)) { + view.destroy(); + return; + } + + var outlets = get(this, '_outlets'); + var container = get(this, 'container'); + var router = container && container.lookup('router:main'); + var renderedName = get(view, 'renderedName'); + + set(outlets, outletName, view); + + if (router && renderedName) { + router._connectActiveView(renderedName, view); + } + }, + + /** + Determines if the view has already been created by checking if + the view has the same constructor, template, and context as the + view in the `_outlets` object. + + @private + @method _hasEquivalentView + @param {String} outletName The name of the outlet we are checking + @param {Object} view An Ember.View + @return {Boolean} + */ + _hasEquivalentView: function(outletName, view) { + var existingView = get(this, '_outlets.'+outletName); + return existingView && + existingView.constructor === view.constructor && + existingView.get('template') === view.get('template') && + existingView.get('context') === view.get('context'); + }, + + /** + Removes an outlet from the view. + + Example + + ```javascript + var MyView = Ember.View.extend({ + template: Ember.Handlebars.compile('Child view: {{outlet "main"}} ') + }); + var myView = MyView.create(); + myView.appendTo('body'); + // myView's html: + //
    Child view:
    + + var FooView = Ember.View.extend({ + template: Ember.Handlebars.compile('

    Foo

    ') + }); + var fooView = FooView.create(); + myView.connectOutlet('main', fooView); + // myView's html: + //
    Child view: + //

    Foo

    + //
    + + myView.disconnectOutlet('main'); + // myView's html: + //
    Child view:
    + ``` + + @method disconnectOutlet + @param {String} outletName The name of the outlet to be removed + */ + disconnectOutlet: function(outletName) { + if (!this._pendingDisconnections) { + this._pendingDisconnections = {}; + } + this._pendingDisconnections[outletName] = true; + run.once(this, '_finishDisconnections'); + }, + + /** + Gets an outlet that is pending disconnection and then + nullifys the object on the `_outlet` object. + + @private + @method _finishDisconnections + */ + _finishDisconnections: function() { + if (this.isDestroyed) return; // _outlets will be gone anyway + var outlets = get(this, '_outlets'); + var pendingDisconnections = this._pendingDisconnections; + this._pendingDisconnections = null; + + for (var outletName in pendingDisconnections) { + set(outlets, outletName, null); + } + } + }); + + __exports__["default"] = EmberView; + }); +enifed("ember-routing/location/api", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // deprecate, assert + var get = __dependency2__.get; + var set = __dependency3__.set; + + /** + @module ember + @submodule ember-routing + */ + + /** + Ember.Location returns an instance of the correct implementation of + the `location` API. + + ## Implementations + + You can pass an implementation name (`hash`, `history`, `none`) to force a + particular implementation to be used in your application. + + ### HashLocation + + Using `HashLocation` results in URLs with a `#` (hash sign) separating the + server side URL portion of the URL from the portion that is used by Ember. + This relies upon the `hashchange` event existing in the browser. + + Example: + + ```javascript + App.Router.map(function() { + this.resource('posts', function() { + this.route('new'); + }); + }); + + App.Router.reopen({ + location: 'hash' + }); + ``` + + This will result in a posts.new url of `/#/posts/new`. + + ### HistoryLocation + + Using `HistoryLocation` results in URLs that are indistinguishable from a + standard URL. This relies upon the browser's `history` API. + + Example: + + ```javascript + App.Router.map(function() { + this.resource('posts', function() { + this.route('new'); + }); + }); + + App.Router.reopen({ + location: 'history' + }); + ``` + + This will result in a posts.new url of `/posts/new`. + + Keep in mind that your server must serve the Ember app at all the routes you + define. + + ### AutoLocation + + Using `AutoLocation`, the router will use the best Location class supported by + the browser it is running in. + + Browsers that support the `history` API will use `HistoryLocation`, those that + do not, but still support the `hashchange` event will use `HashLocation`, and + in the rare case neither is supported will use `NoneLocation`. + + Example: + + ```javascript + App.Router.map(function() { + this.resource('posts', function() { + this.route('new'); + }); + }); + + App.Router.reopen({ + location: 'auto' + }); + ``` + + This will result in a posts.new url of `/posts/new` for modern browsers that + support the `history` api or `/#/posts/new` for older ones, like Internet + Explorer 9 and below. + + When a user visits a link to your application, they will be automatically + upgraded or downgraded to the appropriate `Location` class, with the URL + transformed accordingly, if needed. + + Keep in mind that since some of your users will use `HistoryLocation`, your + server must serve the Ember app at all the routes you define. + + ### NoneLocation + + Using `NoneLocation` causes Ember to not store the applications URL state + in the actual URL. This is generally used for testing purposes, and is one + of the changes made when calling `App.setupForTesting()`. + + ## Location API + + Each location implementation must provide the following methods: + + * implementation: returns the string name used to reference the implementation. + * getURL: returns the current URL. + * setURL(path): sets the current URL. + * replaceURL(path): replace the current URL (optional). + * onUpdateURL(callback): triggers the callback when the URL changes. + * formatURL(url): formats `url` to be placed into `href` attribute. + + Calling setURL or replaceURL will not trigger onUpdateURL callbacks. + + @class Location + @namespace Ember + @static + */ + __exports__["default"] = { + /** + This is deprecated in favor of using the container to lookup the location + implementation as desired. + + For example: + + ```javascript + // Given a location registered as follows: + container.register('location:history-test', HistoryTestLocation); + + // You could create a new instance via: + container.lookup('location:history-test'); + ``` + + @method create + @param {Object} options + @return {Object} an instance of an implementation of the `location` API + @deprecated Use the container to lookup the location implementation that you + need. + */ + create: function(options) { + var implementation = options && options.implementation; + + var implementationClass = this.implementations[implementation]; + + return implementationClass.create.apply(implementationClass, arguments); + }, + + /** + This is deprecated in favor of using the container to register the + location implementation as desired. + + Example: + + ```javascript + Application.initializer({ + name: "history-test-location", + + initialize: function(container, application) { + application.register('location:history-test', HistoryTestLocation); + } + }); + ``` + + @method registerImplementation + @param {String} name + @param {Object} implementation of the `location` API + @deprecated Register your custom location implementation with the + container directly. + */ + registerImplementation: function(name, implementation) { + + this.implementations[name] = implementation; + }, + + implementations: {}, + _location: window.location, + + /** + Returns the current `location.hash` by parsing location.href since browsers + inconsistently URL-decode `location.hash`. + + https://bugzilla.mozilla.org/show_bug.cgi?id=483304 + + @private + @method getHash + @since 1.4.0 + */ + _getHash: function () { + // AutoLocation has it at _location, HashLocation at .location. + // Being nice and not changing + var href = (this._location || this.location).href; + var hashIndex = href.indexOf('#'); + + if (hashIndex === -1) { + return ''; + } else { + return href.substr(hashIndex); + } + } + }; + }); +enifed("ember-routing/location/auto_location", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-routing/location/api","ember-routing/location/history_location","ember-routing/location/hash_location","ember-routing/location/none_location","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES + var get = __dependency2__.get; + var set = __dependency3__.set; + + var EmberLocation = __dependency4__["default"]; + var HistoryLocation = __dependency5__["default"]; + var HashLocation = __dependency6__["default"]; + var NoneLocation = __dependency7__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + /** + Ember.AutoLocation will select the best location option based off browser + support with the priority order: history, hash, none. + + Clean pushState paths accessed by hashchange-only browsers will be redirected + to the hash-equivalent and vice versa so future transitions are consistent. + + Keep in mind that since some of your users will use `HistoryLocation`, your + server must serve the Ember app at all the routes you define. + + @class AutoLocation + @namespace Ember + @static + */ + __exports__["default"] = { + + /** + @private + + This property is used by router:main to know whether to cancel the routing + setup process, which is needed while we redirect the browser. + + @since 1.5.1 + @property cancelRouterSetup + @default false + */ + cancelRouterSetup: false, + + /** + @private + + Will be pre-pended to path upon state change. + + @since 1.5.1 + @property rootURL + @default '/' + */ + rootURL: '/', + + /** + @private + + Attached for mocking in tests + + @since 1.5.1 + @property _window + @default window + */ + _window: window, + + /** + @private + + Attached for mocking in tests + + @property location + @default window.location + */ + _location: window.location, + + /** + @private + + Attached for mocking in tests + + @since 1.5.1 + @property _history + @default window.history + */ + _history: window.history, + + /** + @private + + Attached for mocking in tests + + @since 1.5.1 + @property _HistoryLocation + @default Ember.HistoryLocation + */ + _HistoryLocation: HistoryLocation, + + /** + @private + + Attached for mocking in tests + + @since 1.5.1 + @property _HashLocation + @default Ember.HashLocation + */ + _HashLocation: HashLocation, + + /** + @private + + Attached for mocking in tests + + @since 1.5.1 + @property _NoneLocation + @default Ember.NoneLocation + */ + _NoneLocation: NoneLocation, + + /** + @private + + Returns location.origin or builds it if device doesn't support it. + + @method _getOrigin + */ + _getOrigin: function () { + var location = this._location; + var origin = location.origin; + + // Older browsers, especially IE, don't have origin + if (!origin) { + origin = location.protocol + '//' + location.hostname; + + if (location.port) { + origin += ':' + location.port; + } + } + + return origin; + }, + + /** + @private + + We assume that if the history object has a pushState method, the host should + support HistoryLocation. + + @method _getSupportsHistory + */ + _getSupportsHistory: function () { + // Boosted from Modernizr: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/history.js + // The stock browser on Android 2.2 & 2.3 returns positive on history support + // Unfortunately support is really buggy and there is no clean way to detect + // these bugs, so we fall back to a user agent sniff :( + var userAgent = this._window.navigator.userAgent; + + // We only want Android 2, stock browser, and not Chrome which identifies + // itself as 'Mobile Safari' as well + if (userAgent.indexOf('Android 2') !== -1 && + userAgent.indexOf('Mobile Safari') !== -1 && + userAgent.indexOf('Chrome') === -1) { + return false; + } + + return !!(this._history && 'pushState' in this._history); + }, + + /** + @private + + IE8 running in IE7 compatibility mode gives false positive, so we must also + check documentMode. + + @method _getSupportsHashChange + */ + _getSupportsHashChange: function () { + var _window = this._window; + var documentMode = _window.document.documentMode; + + return ('onhashchange' in _window && (documentMode === undefined || documentMode > 7 )); + }, + + /** + @private + + Redirects the browser using location.replace, prepending the locatin.origin + to prevent phishing attempts + + @method _replacePath + */ + _replacePath: function (path) { + this._location.replace(this._getOrigin() + path); + }, + + /** + @since 1.5.1 + @private + @method _getRootURL + */ + _getRootURL: function () { + return this.rootURL; + }, + + /** + @private + + Returns the current `location.pathname`, normalized for IE inconsistencies. + + @method _getPath + */ + _getPath: function () { + var pathname = this._location.pathname; + // Various versions of IE/Opera don't always return a leading slash + if (pathname.charAt(0) !== '/') { + pathname = '/' + pathname; + } + + return pathname; + }, + + /** + @private + + Returns normalized location.hash as an alias to Ember.Location._getHash + + @since 1.5.1 + @method _getHash + */ + _getHash: EmberLocation._getHash, + + /** + @private + + Returns location.search + + @since 1.5.1 + @method _getQuery + */ + _getQuery: function () { + return this._location.search; + }, + + /** + @private + + Returns the full pathname including query and hash + + @method _getFullPath + */ + _getFullPath: function () { + return this._getPath() + this._getQuery() + this._getHash(); + }, + + /** + @private + + Returns the current path as it should appear for HistoryLocation supported + browsers. This may very well differ from the real current path (e.g. if it + starts off as a hashed URL) + + @method _getHistoryPath + */ + _getHistoryPath: function () { + var rootURL = this._getRootURL(); + var path = this._getPath(); + var hash = this._getHash(); + var query = this._getQuery(); + var rootURLIndex = path.indexOf(rootURL); + var routeHash, hashParts; + + + // By convention, Ember.js routes using HashLocation are required to start + // with `#/`. Anything else should NOT be considered a route and should + // be passed straight through, without transformation. + if (hash.substr(0, 2) === '#/') { + // There could be extra hash segments after the route + hashParts = hash.substr(1).split('#'); + // The first one is always the route url + routeHash = hashParts.shift(); + + // If the path already has a trailing slash, remove the one + // from the hashed route so we don't double up. + if (path.slice(-1) === '/') { + routeHash = routeHash.substr(1); + } + + // This is the "expected" final order + path += routeHash; + path += query; + + if (hashParts.length) { + path += '#' + hashParts.join('#'); + } + } else { + path += query; + path += hash; + } + + return path; + }, + + /** + @private + + Returns the current path as it should appear for HashLocation supported + browsers. This may very well differ from the real current path. + + @method _getHashPath + */ + _getHashPath: function () { + var rootURL = this._getRootURL(); + var path = rootURL; + var historyPath = this._getHistoryPath(); + var routePath = historyPath.substr(rootURL.length); + + if (routePath !== '') { + if (routePath.charAt(0) !== '/') { + routePath = '/' + routePath; + } + + path += '#' + routePath; + } + + return path; + }, + + /** + Selects the best location option based off browser support and returns an + instance of that Location class. + + @see Ember.AutoLocation + @method create + */ + create: function (options) { + if (options && options.rootURL) { + this.rootURL = options.rootURL; + } + + var historyPath, hashPath; + var cancelRouterSetup = false; + var implementationClass = this._NoneLocation; + var currentPath = this._getFullPath(); + + if (this._getSupportsHistory()) { + historyPath = this._getHistoryPath(); + + // Since we support history paths, let's be sure we're using them else + // switch the location over to it. + if (currentPath === historyPath) { + implementationClass = this._HistoryLocation; + } else { + + if (currentPath.substr(0, 2) === '/#') { + this._history.replaceState({ path: historyPath }, null, historyPath); + implementationClass = this._HistoryLocation; + } else { + cancelRouterSetup = true; + this._replacePath(historyPath); + } + } + + } else if (this._getSupportsHashChange()) { + hashPath = this._getHashPath(); + + // Be sure we're using a hashed path, otherwise let's switch over it to so + // we start off clean and consistent. We'll count an index path with no + // hash as "good enough" as well. + if (currentPath === hashPath || (currentPath === '/' && hashPath === '/#/')) { + implementationClass = this._HashLocation; + } else { + // Our URL isn't in the expected hash-supported format, so we want to + // cancel the router setup and replace the URL to start off clean + cancelRouterSetup = true; + this._replacePath(hashPath); + } + } + + var implementation = implementationClass.create.apply(implementationClass, arguments); + + if (cancelRouterSetup) { + set(implementation, 'cancelRouterSetup', true); + } + + return implementation; + } + }; + }); +enifed("ember-routing/location/hash_location", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/run_loop","ember-metal/utils","ember-runtime/system/object","ember-routing/location/api","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var get = __dependency2__.get; + var set = __dependency3__.set; + var run = __dependency4__["default"]; + var guidFor = __dependency5__.guidFor; + + var EmberObject = __dependency6__["default"]; + var EmberLocation = __dependency7__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + /** + `Ember.HashLocation` implements the location API using the browser's + hash. At present, it relies on a `hashchange` event existing in the + browser. + + @class HashLocation + @namespace Ember + @extends Ember.Object + */ + __exports__["default"] = EmberObject.extend({ + implementation: 'hash', + + init: function() { + set(this, 'location', get(this, '_location') || window.location); + }, + + /** + @private + + Returns normalized location.hash + + @since 1.5.1 + @method getHash + */ + getHash: EmberLocation._getHash, + + /** + Returns the current `location.hash`, minus the '#' at the front. + + @private + @method getURL + */ + getURL: function() { + var path = this.getHash().substr(1); + return path; + }, + + /** + Set the `location.hash` and remembers what was set. This prevents + `onUpdateURL` callbacks from triggering when the hash was set by + `HashLocation`. + + @private + @method setURL + @param path {String} + */ + setURL: function(path) { + get(this, 'location').hash = path; + set(this, 'lastSetURL', path); + }, + + /** + Uses location.replace to update the url without a page reload + or history modification. + + @private + @method replaceURL + @param path {String} + */ + replaceURL: function(path) { + get(this, 'location').replace('#' + path); + set(this, 'lastSetURL', path); + }, + + /** + Register a callback to be invoked when the hash changes. These + callbacks will execute when the user presses the back or forward + button, but not after `setURL` is invoked. + + @private + @method onUpdateURL + @param callback {Function} + */ + onUpdateURL: function(callback) { + var self = this; + var guid = guidFor(this); + + Ember.$(window).on('hashchange.ember-location-'+guid, function() { + run(function() { + var path = self.getURL(); + if (get(self, 'lastSetURL') === path) { return; } + + set(self, 'lastSetURL', null); + + callback(path); + }); + }); + }, + + /** + Given a URL, formats it to be placed into the page as part + of an element's `href` attribute. + + This is used, for example, when using the {{action}} helper + to generate a URL based on an event. + + @private + @method formatURL + @param url {String} + */ + formatURL: function(url) { + return '#' + url; + }, + + /** + Cleans up the HashLocation event listener. + + @private + @method willDestroy + */ + willDestroy: function() { + var guid = guidFor(this); + + Ember.$(window).off('hashchange.ember-location-'+guid); + } + }); + }); +enifed("ember-routing/location/history_location", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-runtime/system/object","ember-views/system/jquery","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES + var get = __dependency2__.get; + var set = __dependency3__.set; + var guidFor = __dependency4__.guidFor; + + var EmberObject = __dependency5__["default"]; + var jQuery = __dependency6__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + var popstateFired = false; + var supportsHistoryState = window.history && 'state' in window.history; + + /** + Ember.HistoryLocation implements the location API using the browser's + history.pushState API. + + @class HistoryLocation + @namespace Ember + @extends Ember.Object + */ + __exports__["default"] = EmberObject.extend({ + implementation: 'history', + + init: function() { + set(this, 'location', get(this, 'location') || window.location); + set(this, 'baseURL', jQuery('base').attr('href') || ''); + }, + + /** + Used to set state on first call to setURL + + @private + @method initState + */ + initState: function() { + set(this, 'history', get(this, 'history') || window.history); + this.replaceState(this.formatURL(this.getURL())); + }, + + /** + Will be pre-pended to path upon state change + + @property rootURL + @default '/' + */ + rootURL: '/', + + /** + Returns the current `location.pathname` without `rootURL` or `baseURL` + + @private + @method getURL + @return url {String} + */ + getURL: function() { + var rootURL = get(this, 'rootURL'); + var location = get(this, 'location'); + var path = location.pathname; + var baseURL = get(this, 'baseURL'); + + rootURL = rootURL.replace(/\/$/, ''); + baseURL = baseURL.replace(/\/$/, ''); + + var url = path.replace(baseURL, '').replace(rootURL, ''); + var search = location.search || ''; + + url += search; + + return url; + }, + + /** + Uses `history.pushState` to update the url without a page reload. + + @private + @method setURL + @param path {String} + */ + setURL: function(path) { + var state = this.getState(); + path = this.formatURL(path); + + if (!state || state.path !== path) { + this.pushState(path); + } + }, + + /** + Uses `history.replaceState` to update the url without a page reload + or history modification. + + @private + @method replaceURL + @param path {String} + */ + replaceURL: function(path) { + var state = this.getState(); + path = this.formatURL(path); + + if (!state || state.path !== path) { + this.replaceState(path); + } + }, + + /** + Get the current `history.state`. Checks for if a polyfill is + required and if so fetches this._historyState. The state returned + from getState may be null if an iframe has changed a window's + history. + + @private + @method getState + @return state {Object} + */ + getState: function() { + return supportsHistoryState ? get(this, 'history').state : this._historyState; + }, + + /** + Pushes a new state. + + @private + @method pushState + @param path {String} + */ + pushState: function(path) { + var state = { path: path }; + + get(this, 'history').pushState(state, null, path); + + // store state if browser doesn't support `history.state` + if (!supportsHistoryState) { + this._historyState = state; + } + + // used for webkit workaround + this._previousURL = this.getURL(); + }, + + /** + Replaces the current state. + + @private + @method replaceState + @param path {String} + */ + replaceState: function(path) { + var state = { path: path }; + + get(this, 'history').replaceState(state, null, path); + + // store state if browser doesn't support `history.state` + if (!supportsHistoryState) { + this._historyState = state; + } + + // used for webkit workaround + this._previousURL = this.getURL(); + }, + + /** + Register a callback to be invoked whenever the browser + history changes, including using forward and back buttons. + + @private + @method onUpdateURL + @param callback {Function} + */ + onUpdateURL: function(callback) { + var guid = guidFor(this); + var self = this; + + jQuery(window).on('popstate.ember-location-'+guid, function(e) { + // Ignore initial page load popstate event in Chrome + if (!popstateFired) { + popstateFired = true; + if (self.getURL() === self._previousURL) { return; } + } + callback(self.getURL()); + }); + }, + + /** + Used when using `{{action}}` helper. The url is always appended to the rootURL. + + @private + @method formatURL + @param url {String} + @return formatted url {String} + */ + formatURL: function(url) { + var rootURL = get(this, 'rootURL'); + var baseURL = get(this, 'baseURL'); + + if (url !== '') { + rootURL = rootURL.replace(/\/$/, ''); + baseURL = baseURL.replace(/\/$/, ''); + } else if(baseURL.match(/^\//) && rootURL.match(/^\//)) { + baseURL = baseURL.replace(/\/$/, ''); + } + + return baseURL + rootURL + url; + }, + + /** + Cleans up the HistoryLocation event listener. + + @private + @method willDestroy + */ + willDestroy: function() { + var guid = guidFor(this); + + jQuery(window).off('popstate.ember-location-'+guid); + } + }); + }); +enifed("ember-routing/location/none_location", + ["ember-metal/property_get","ember-metal/property_set","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var set = __dependency2__.set; + var EmberObject = __dependency3__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + /** + Ember.NoneLocation does not interact with the browser. It is useful for + testing, or when you need to manage state with your Router, but temporarily + don't want it to muck with the URL (for example when you embed your + application in a larger page). + + @class NoneLocation + @namespace Ember + @extends Ember.Object + */ + __exports__["default"] = EmberObject.extend({ + implementation: 'none', + path: '', + + /** + Returns the current path. + + @private + @method getURL + @return {String} path + */ + getURL: function() { + return get(this, 'path'); + }, + + /** + Set the path and remembers what was set. Using this method + to change the path will not invoke the `updateURL` callback. + + @private + @method setURL + @param path {String} + */ + setURL: function(path) { + set(this, 'path', path); + }, + + /** + Register a callback to be invoked when the path changes. These + callbacks will execute when the user presses the back or forward + button, but not after `setURL` is invoked. + + @private + @method onUpdateURL + @param callback {Function} + */ + onUpdateURL: function(callback) { + this.updateCallback = callback; + }, + + /** + Sets the path and calls the `updateURL` callback. + + @private + @method handleURL + @param callback {Function} + */ + handleURL: function(url) { + set(this, 'path', url); + this.updateCallback(url); + }, + + /** + Given a URL, formats it to be placed into the page as part + of an element's `href` attribute. + + This is used, for example, when using the {{action}} helper + to generate a URL based on an event. + + @private + @method formatURL + @param url {String} + @return {String} url + */ + formatURL: function(url) { + // The return value is not overly meaningful, but we do not want to throw + // errors when test code renders templates containing {{action href=true}} + // helpers. + return url; + } + }); + }); +enifed("ember-routing/system/cache", + ["ember-runtime/system/object","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var EmberObject = __dependency1__["default"]; + + __exports__["default"] = EmberObject.extend({ + init: function() { + this.cache = {}; + }, + has: function(bucketKey) { + return bucketKey in this.cache; + }, + stash: function(bucketKey, key, value) { + var bucket = this.cache[bucketKey]; + if (!bucket) { + bucket = this.cache[bucketKey] = {}; + } + bucket[key] = value; + }, + lookup: function(bucketKey, prop, defaultValue) { + var cache = this.cache; + if (!(bucketKey in cache)) { + return defaultValue; + } + var bucket = cache[bucketKey]; + if (prop in bucket) { + return bucket[prop]; + } else { + return defaultValue; + } + }, + cache: null + }); + }); +enifed("ember-routing/system/controller_for", + ["exports"], + function(__exports__) { + "use strict"; + /** + @module ember + @submodule ember-routing + */ + + /** + + Finds a controller instance. + + @for Ember + @method controllerFor + @private + */ + __exports__["default"] = function controllerFor(container, controllerName, lookupOptions) { + return container.lookup('controller:' + controllerName, lookupOptions); + } + }); +enifed("ember-routing/system/dsl", + ["ember-metal/core","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES, assert + + /** + @module ember + @submodule ember-routing + */ + + function DSL(name) { + this.parent = name; + this.matches = []; + } + __exports__["default"] = DSL; + + DSL.prototype = { + route: function(name, options, callback) { + if (arguments.length === 2 && typeof options === 'function') { + callback = options; + options = {}; + } + + if (arguments.length === 1) { + options = {}; + } + + var type = options.resetNamespace === true ? 'resource' : 'route'; + + + if (typeof options.path !== 'string') { + options.path = "/" + name; + } + + if (canNest(this) && options.resetNamespace !== true) { + name = this.parent + "." + name; + } + + if (callback) { + var dsl = new DSL(name); + route(dsl, 'loading'); + route(dsl, 'error', { path: "/_unused_dummy_error_path_route_" + name + "/:error" }); + + if (callback) { callback.call(dsl); } + + this.push(options.path, name, dsl.generate()); + } else { + this.push(options.path, name, null); + } + + }, + + push: function(url, name, callback) { + var parts = name.split('.'); + if (url === "" || url === "/" || parts[parts.length-1] === "index") { this.explicitIndex = true; } + + this.matches.push([url, name, callback]); + }, + + resource: function(name, options, callback) { + if (arguments.length === 2 && typeof options === 'function') { + callback = options; + options = {}; + } + + if (arguments.length === 1) { + options = {}; + } + + options.resetNamespace = true; + this.route(name, options, callback); + }, + + generate: function() { + var dslMatches = this.matches; + + if (!this.explicitIndex) { + route(this, "index", { path: "/" }); + } + + return function(match) { + for (var i=0, l=dslMatches.length; i +
    + {{outlet "anOutletName"}} +
    + ``` + + ```handlebars + +

    Photos

    + ``` + + You can render `photos.hbs` into the `"anOutletName"` outlet of + `application.hbs` by calling `render`: + + ```js + // posts route + Ember.Route.extend({ + renderTemplate: function(){ + this.render('posts', { + into: 'application', + outlet: 'anOutletName' + }) + } + }); + ``` + + `render` additionally allows you to supply which `view`, `controller`, and + `model` objects should be loaded and associated with the rendered template. + + + ```js + // posts route + Ember.Route.extend({ + renderTemplate: function(controller, model){ + this.render('posts', { // the template to render, referenced by name + into: 'application', // the template to render into, referenced by name + outlet: 'anOutletName', // the outlet inside `options.template` to render into. + view: 'aViewName', // the view to use for this template, referenced by name + controller: 'someControllerName', // the controller to use for this template, referenced by name + model: model // the model to set on `options.controller`. + }) + } + }); + ``` + + The string values provided for the template name, view, and controller + will eventually pass through to the resolver for lookup. See + Ember.Resolver for how these are mapped to JavaScript objects in your + application. + + Not all options need to be passed to `render`. Default values will be used + based on the name of the route specified in the router or the Route's + `controllerName`, `viewName` and and `templateName` properties. + + For example: + + ```js + // router + Router.map(function() { + this.route('index'); + this.resource('post', {path: '/posts/:post_id'}); + }); + ``` + + ```js + // post route + PostRoute = App.Route.extend({ + renderTemplate: function() { + this.render(); // all defaults apply + } + }); + ``` + + The name of the `PostRoute`, defined by the router, is `post`. + + The following equivalent default options will be applied when + the Route calls `render`: + + ```js + // + this.render('post', { // the template name associated with 'post' Route + into: 'application', // the parent route to 'post' Route + outlet: 'main', // {{outlet}} and {{outlet 'main' are synonymous}}, + view: 'post', // the view associated with the 'post' Route + controller: 'post', // the controller associated with the 'post' Route + }) + ``` + + By default the controller's `model` will be the route's model, so it does not + need to be passed unless you wish to change which model is being used. + + @method render + @param {String} name the name of the template to render + @param {Object} [options] the options + @param {String} [options.into] the template to render into, + referenced by name. Defaults to the parent template + @param {String} [options.outlet] the outlet inside `options.template` to render into. + Defaults to 'main' + @param {String} [options.controller] the controller to use for this template, + referenced by name. Defaults to the Route's paired controller + @param {String} [options.model] the model object to set on `options.controller` + Defaults to the return value of the Route's model hook + */ + render: function(name, options) { + + var namePassed = typeof name === 'string' && !!name; + + if (typeof name === 'object' && !options) { + options = name; + name = this.routeName; + } + + options = options || {}; + options.namePassed = namePassed; + + var templateName; + + if (name) { + name = name.replace(/\//g, '.'); + templateName = name; + } else { + name = this.routeName; + templateName = this.templateName || name; + } + + var viewName = options.view || namePassed && name || this.viewName || name; + + var container = this.container; + var view = container.lookup('view:' + viewName); + var template = view ? view.get('template') : null; + + if (!template) { + template = container.lookup('template:' + templateName); + } + + if (!view && !template) { + if (get(this.router, 'namespace.LOG_VIEW_LOOKUPS')) { + } + return; + } + + options = normalizeOptions(this, name, template, options); + view = setupView(view, container, options); + + if (options.outlet === 'main') { this.lastRenderedTemplate = name; } + + appendView(this, view, options); + }, + + /** + Disconnects a view that has been rendered into an outlet. + + You may pass any or all of the following options to `disconnectOutlet`: + + * `outlet`: the name of the outlet to clear (default: 'main') + * `parentView`: the name of the view containing the outlet to clear + (default: the view rendered by the parent route) + + Example: + + ```js + App.ApplicationRoute = App.Route.extend({ + actions: { + showModal: function(evt) { + this.render(evt.modalName, { + outlet: 'modal', + into: 'application' + }); + }, + hideModal: function(evt) { + this.disconnectOutlet({ + outlet: 'modal', + parentView: 'application' + }); + } + } + }); + ``` + + Alternatively, you can pass the `outlet` name directly as a string. + + Example: + + ```js + hideModal: function(evt) { + this.disconnectOutlet('modal'); + } + ``` + + @method disconnectOutlet + @param {Object|String} options the options hash or outlet name + */ + disconnectOutlet: function(options) { + if (!options || typeof options === "string") { + var outletName = options; + options = {}; + options.outlet = outletName; + } + options.parentView = options.parentView ? options.parentView.replace(/\//g, '.') : parentTemplate(this); + options.outlet = options.outlet || 'main'; + + var parentView = this.router._lookupActiveView(options.parentView); + if (parentView) { parentView.disconnectOutlet(options.outlet); } + }, + + willDestroy: function() { + this.teardownViews(); + }, + + /** + @private + + @method teardownViews + */ + teardownViews: function() { + // Tear down the top level view + if (this.teardownTopLevelView) { this.teardownTopLevelView(); } + + // Tear down any outlets rendered with 'into' + var teardownOutletViews = this.teardownOutletViews || []; + forEach(teardownOutletViews, function(teardownOutletView) { + teardownOutletView(); + }); + + delete this.teardownTopLevelView; + delete this.teardownOutletViews; + delete this.lastRenderedTemplate; + } + }); + + var defaultQPMeta = { + qps: [], + map: {}, + states: {} + }; + + function parentRoute(route) { + var handlerInfo = handlerInfoFor(route, route.router.router.state.handlerInfos, -1); + return handlerInfo && handlerInfo.handler; + } + + function handlerInfoFor(route, handlerInfos, _offset) { + if (!handlerInfos) { return; } + + var offset = _offset || 0, current; + for (var i=0, l=handlerInfos.length; i 1) { + var qp0 = qps[0].qp, qp1=qps[1].qp; + } + var qp = qps[0].qp; + queryParams[qp.urlKey] = qp.route.serializeQueryParam(qps[0].value, qp.urlKey, qp.type); + } + }, + + _deserializeQueryParams: function(targetRouteName, queryParams) { + forEachQueryParam(this, targetRouteName, queryParams, function(key, value, qp) { + delete queryParams[key]; + queryParams[qp.prop] = qp.route.deserializeQueryParam(value, qp.urlKey, qp.type); + }); + }, + + _pruneDefaultQueryParamValues: function(targetRouteName, queryParams) { + var qps = this._queryParamsFor(targetRouteName); + for (var key in queryParams) { + var qp = qps.map[key]; + if (qp && qp.sdef === queryParams[key]) { + delete queryParams[key]; + } + } + }, + + _doTransition: function(_targetRouteName, models, _queryParams) { + var targetRouteName = _targetRouteName || getActiveTargetName(this.router); + + var queryParams = {}; + merge(queryParams, _queryParams); + this._prepareQueryParams(targetRouteName, models, queryParams); + + var transitionArgs = routeArgs(targetRouteName, models, queryParams); + var transitionPromise = this.router.transitionTo.apply(this.router, transitionArgs); + + listenForTransitionErrors(transitionPromise); + + return transitionPromise; + }, + + _prepareQueryParams: function(targetRouteName, models, queryParams) { + this._hydrateUnsuppliedQueryParams(targetRouteName, models, queryParams); + this._serializeQueryParams(targetRouteName, queryParams); + this._pruneDefaultQueryParamValues(targetRouteName, queryParams); + }, + + /** + Returns a merged query params meta object for a given route. + Useful for asking a route what its known query params are. + */ + _queryParamsFor: function(leafRouteName) { + if (this._qpCache[leafRouteName]) { + return this._qpCache[leafRouteName]; + } + + var map = {}, qps = [], qpCache = this._qpCache[leafRouteName] = { + map: map, + qps: qps + }; + + var routerjs = this.router; + var recogHandlerInfos = routerjs.recognizer.handlersFor(leafRouteName); + + for (var i = 0, len = recogHandlerInfos.length; i < len; ++i) { + var recogHandler = recogHandlerInfos[i]; + var route = routerjs.getHandler(recogHandler.handler); + var qpMeta = get(route, '_qp'); + + if (!qpMeta) { continue; } + + merge(map, qpMeta.map); + qps.push.apply(qps, qpMeta.qps); + } + + return { + qps: qps, + map: map + }; + }, + + /* + becomeResolved: function(payload, resolvedContext) { + var params = this.serialize(resolvedContext); + + if (payload) { + this.stashResolvedModel(payload, resolvedContext); + payload.params = payload.params || {}; + payload.params[this.name] = params; + } + + return this.factory('resolved', { + context: resolvedContext, + name: this.name, + handler: this.handler, + params: params + }); + }, + */ + + _hydrateUnsuppliedQueryParams: function(leafRouteName, contexts, queryParams) { + var state = calculatePostTransitionState(this, leafRouteName, contexts); + var handlerInfos = state.handlerInfos; + var appCache = this._bucketCache; + + stashParamNames(this, handlerInfos); + + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var route = handlerInfos[i].handler; + var qpMeta = get(route, '_qp'); + + for (var j = 0, qpLen = qpMeta.qps.length; j < qpLen; ++j) { + var qp = qpMeta.qps[j]; + var presentProp = qp.prop in queryParams && qp.prop || + qp.fprop in queryParams && qp.fprop; + + if (presentProp) { + if (presentProp !== qp.fprop) { + queryParams[qp.fprop] = queryParams[presentProp]; + delete queryParams[presentProp]; + } + } else { + var controllerProto = qp.cProto; + var cacheMeta = get(controllerProto, '_cacheMeta'); + + var cacheKey = controllerProto._calculateCacheKey(qp.ctrl, cacheMeta[qp.prop].parts, state.params); + queryParams[qp.fprop] = appCache.lookup(cacheKey, qp.prop, qp.def); + } + } + } + }, + + _scheduleLoadingEvent: function(transition, originRoute) { + this._cancelLoadingEvent(); + this._loadingStateTimer = run.scheduleOnce('routerTransitions', this, '_fireLoadingEvent', transition, originRoute); + }, + + _fireLoadingEvent: function(transition, originRoute) { + if (!this.router.activeTransition) { + // Don't fire an event if we've since moved on from + // the transition that put us in a loading state. + return; + } + + transition.trigger(true, 'loading', transition, originRoute); + }, + + _cancelLoadingEvent: function () { + if (this._loadingStateTimer) { + run.cancel(this._loadingStateTimer); + } + this._loadingStateTimer = null; + } + }); + + /* + Helper function for iterating root-ward, starting + from (but not including) the provided `originRoute`. + + Returns true if the last callback fired requested + to bubble upward. + + @private + */ + function forEachRouteAbove(originRoute, transition, callback) { + var handlerInfos = transition.state.handlerInfos; + var originRouteFound = false; + var handlerInfo, route; + + for (var i = handlerInfos.length - 1; i >= 0; --i) { + handlerInfo = handlerInfos[i]; + route = handlerInfo.handler; + + if (!originRouteFound) { + if (originRoute === route) { + originRouteFound = true; + } + continue; + } + + if (callback(route, handlerInfos[i + 1].handler) !== true) { + return false; + } + } + return true; + } + + // These get invoked when an action bubbles above ApplicationRoute + // and are not meant to be overridable. + var defaultActionHandlers = { + + willResolveModel: function(transition, originRoute) { + originRoute.router._scheduleLoadingEvent(transition, originRoute); + }, + + error: function(error, transition, originRoute) { + // Attempt to find an appropriate error substate to enter. + var router = originRoute.router; + + var tryTopLevel = forEachRouteAbove(originRoute, transition, function(route, childRoute) { + var childErrorRouteName = findChildRouteName(route, childRoute, 'error'); + if (childErrorRouteName) { + router.intermediateTransitionTo(childErrorRouteName, error); + return; + } + return true; + }); + + if (tryTopLevel) { + // Check for top-level error state to enter. + if (routeHasBeenDefined(originRoute.router, 'application_error')) { + router.intermediateTransitionTo('application_error', error); + return; + } + } + + logError(error, 'Error while processing route: ' + transition.targetName); + }, + + loading: function(transition, originRoute) { + // Attempt to find an appropriate loading substate to enter. + var router = originRoute.router; + + var tryTopLevel = forEachRouteAbove(originRoute, transition, function(route, childRoute) { + var childLoadingRouteName = findChildRouteName(route, childRoute, 'loading'); + + if (childLoadingRouteName) { + router.intermediateTransitionTo(childLoadingRouteName); + return; + } + + // Don't bubble above pivot route. + if (transition.pivotHandler !== route) { + return true; + } + }); + + if (tryTopLevel) { + // Check for top-level loading state to enter. + if (routeHasBeenDefined(originRoute.router, 'application_loading')) { + router.intermediateTransitionTo('application_loading'); + return; + } + } + } + }; + + function logError(error, initialMessage) { + var errorArgs = []; + + if (initialMessage) { errorArgs.push(initialMessage); } + + if (error) { + if (error.message) { errorArgs.push(error.message); } + if (error.stack) { errorArgs.push(error.stack); } + + if (typeof error === "string") { errorArgs.push(error); } + } + + Ember.Logger.error.apply(this, errorArgs); + } + + function findChildRouteName(parentRoute, originatingChildRoute, name) { + var router = parentRoute.router; + var childName; + var targetChildRouteName = originatingChildRoute.routeName.split('.').pop(); + var namespace = parentRoute.routeName === 'application' ? '' : parentRoute.routeName + '.'; + + + // Second, try general loading state, e.g. 'loading' + childName = namespace + name; + if (routeHasBeenDefined(router, childName)) { + return childName; + } + } + + function routeHasBeenDefined(router, name) { + var container = router.container; + return router.hasRoute(name) && + (container.has('template:' + name) || container.has('route:' + name)); + } + + function triggerEvent(handlerInfos, ignoreFailure, args) { + var name = args.shift(); + + if (!handlerInfos) { + if (ignoreFailure) { return; } + throw new EmberError("Can't trigger action '" + name + "' because your app hasn't finished transitioning into its first route. To trigger an action on destination routes during a transition, you can call `.send()` on the `Transition` object passed to the `model/beforeModel/afterModel` hooks."); + } + + var eventWasHandled = false; + var handlerInfo, handler; + + for (var i = handlerInfos.length - 1; i >= 0; i--) { + handlerInfo = handlerInfos[i]; + handler = handlerInfo.handler; + + if (handler._actions && handler._actions[name]) { + if (handler._actions[name].apply(handler, args) === true) { + eventWasHandled = true; + } else { + return; + } + } + } + + if (defaultActionHandlers[name]) { + defaultActionHandlers[name].apply(null, args); + return; + } + + if (!eventWasHandled && !ignoreFailure) { + throw new EmberError("Nothing handled the action '" + name + "'. If you did handle the action, this error can be caused by returning true from an action handler in a controller, causing the action to bubble."); + } + } + + function calculatePostTransitionState(emberRouter, leafRouteName, contexts) { + var routerjs = emberRouter.router; + var state = routerjs.applyIntent(leafRouteName, contexts); + var handlerInfos = state.handlerInfos; + var params = state.params; + + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var handlerInfo = handlerInfos[i]; + if (!handlerInfo.isResolved) { + handlerInfo = handlerInfo.becomeResolved(null, handlerInfo.context); + } + params[handlerInfo.name] = handlerInfo.params; + } + return state; + } + + function updatePaths(router) { + var appController = router.container.lookup('controller:application'); + + if (!appController) { + // appController might not exist when top-level loading/error + // substates have been entered since ApplicationRoute hasn't + // actually been entered at that point. + return; + } + + var infos = router.router.currentHandlerInfos; + var path = EmberRouter._routePath(infos); + + if (!('currentPath' in appController)) { + defineProperty(appController, 'currentPath'); + } + + set(appController, 'currentPath', path); + + if (!('currentRouteName' in appController)) { + defineProperty(appController, 'currentRouteName'); + } + + set(appController, 'currentRouteName', infos[infos.length - 1].name); + } + + EmberRouter.reopenClass({ + router: null, + + /** + The `Router.map` function allows you to define mappings from URLs to routes + and resources in your application. These mappings are defined within the + supplied callback function using `this.resource` and `this.route`. + + ```javascript + App.Router.map(function({ + this.route('about'); + this.resource('article'); + })); + ``` + + For more detailed examples please see + [the guides](http://emberjs.com/guides/routing/defining-your-routes/). + + @method map + @param callback + */ + map: function(callback) { + var router = this.router; + if (!router) { + router = new Router(); + + + router._triggerWillChangeContext = Ember.K; + router._triggerWillLeave = Ember.K; + + + router.callbacks = []; + router.triggerEvent = triggerEvent; + this.reopenClass({ router: router }); + } + + var dsl = EmberRouterDSL.map(function() { + this.resource('application', { path: "/" }, function() { + for (var i=0; i < router.callbacks.length; i++) { + router.callbacks[i].call(this); + } + callback.call(this); + }); + }); + + router.callbacks.push(callback); + router.map(dsl.generate()); + return router; + }, + + _routePath: function(handlerInfos) { + var path = []; + + // We have to handle coalescing resource names that + // are prefixed with their parent's names, e.g. + // ['foo', 'foo.bar.baz'] => 'foo.bar.baz', not 'foo.foo.bar.baz' + + function intersectionMatches(a1, a2) { + for (var i = 0, len = a1.length; i < len; ++i) { + if (a1[i] !== a2[i]) { + return false; + } + } + return true; + } + + var name, nameParts, oldNameParts; + for (var i=1, l=handlerInfos.length; i 0) - (diff < 0); + } + + /** + This will compare two javascript values of possibly different types. + It will tell you which one is greater than the other by returning: + + - -1 if the first is smaller than the second, + - 0 if both are equal, + - 1 if the first is greater than the second. + + The order is calculated based on `Ember.ORDER_DEFINITION`, if types are different. + In case they have the same type an appropriate comparison for this type is made. + + ```javascript + Ember.compare('hello', 'hello'); // 0 + Ember.compare('abc', 'dfg'); // -1 + Ember.compare(2, 1); // 1 + ``` + + @method compare + @for Ember + @param {Object} v First value to compare + @param {Object} w Second value to compare + @return {Number} -1 if v < w, 0 if v = w and 1 if v > w. + */ + __exports__["default"] = function compare(v, w) { + if (v === w) { + return 0; + } + + var type1 = typeOf(v); + var type2 = typeOf(w); + + if (Comparable) { + if (type1 ==='instance' && Comparable.detect(v.constructor)) { + return v.constructor.compare(v, w); + } + + if (type2 === 'instance' && Comparable.detect(w.constructor)) { + return 1 - w.constructor.compare(w, v); + } + } + + var res = spaceship(TYPE_ORDER[type1], TYPE_ORDER[type2]); + if (res !== 0) { + return res; + } + + // types are equal - so we have to check values now + switch (type1) { + case 'boolean': + case 'number': + return spaceship(v,w); + + case 'string': + return spaceship(v.localeCompare(w), 0); + + case 'array': + var vLen = v.length; + var wLen = w.length; + var len = Math.min(vLen, wLen); + + for (var i = 0; i < len; i++) { + var r = compare(v[i], w[i]); + if (r !== 0) { + return r; + } + } + + // all elements are equal now + // shorter array should be ordered first + return spaceship(vLen, wLen); + + case 'instance': + if (Comparable && Comparable.detect(v)) { + return v.compare(v, w); + } + return 0; + + case 'date': + return spaceship(v.getTime(), w.getTime()); + + default: + return 0; + } + } + }); +enifed("ember-runtime/computed/array_computed", + ["ember-metal/core","ember-runtime/computed/reduce_computed","ember-metal/enumerable_utils","ember-metal/platform","ember-metal/observer","ember-metal/error","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var reduceComputed = __dependency2__.reduceComputed; + var ReduceComputedProperty = __dependency2__.ReduceComputedProperty; + var forEach = __dependency3__.forEach; + var o_create = __dependency4__.create; + var addObserver = __dependency5__.addObserver; + var EmberError = __dependency6__["default"]; + + var a_slice = [].slice; + + function ArrayComputedProperty() { + var cp = this; + + ReduceComputedProperty.apply(this, arguments); + + this.func = (function(reduceFunc) { + return function (propertyName) { + if (!cp._hasInstanceMeta(this, propertyName)) { + // When we recompute an array computed property, we need already + // retrieved arrays to be updated; we can't simply empty the cache and + // hope the array is re-retrieved. + forEach(cp._dependentKeys, function(dependentKey) { + addObserver(this, dependentKey, function() { + cp.recomputeOnce.call(this, propertyName); + }); + }, this); + } + + return reduceFunc.apply(this, arguments); + }; + })(this.func); + + return this; + } + + ArrayComputedProperty.prototype = o_create(ReduceComputedProperty.prototype); + + ArrayComputedProperty.prototype.initialValue = function () { + return Ember.A(); + }; + + ArrayComputedProperty.prototype.resetValue = function (array) { + array.clear(); + return array; + }; + + // This is a stopgap to keep the reference counts correct with lazy CPs. + ArrayComputedProperty.prototype.didChange = function (obj, keyName) { + return; + }; + + /** + Creates a computed property which operates on dependent arrays and + is updated with "one at a time" semantics. When items are added or + removed from the dependent array(s) an array computed only operates + on the change instead of re-evaluating the entire array. This should + return an array, if you'd like to use "one at a time" semantics and + compute some value other then an array look at + `Ember.reduceComputed`. + + If there are more than one arguments the first arguments are + considered to be dependent property keys. The last argument is + required to be an options object. The options object can have the + following three properties. + + `initialize` - An optional initialize function. Typically this will be used + to set up state on the instanceMeta object. + + `removedItem` - A function that is called each time an element is + removed from the array. + + `addedItem` - A function that is called each time an element is + added to the array. + + + The `initialize` function has the following signature: + + ```javascript + function(array, changeMeta, instanceMeta) + ``` + + `array` - The initial value of the arrayComputed, an empty array. + + `changeMeta` - An object which contains meta information about the + computed. It contains the following properties: + + - `property` the computed property + - `propertyName` the name of the property on the object + + `instanceMeta` - An object that can be used to store meta + information needed for calculating your computed. For example a + unique computed might use this to store the number of times a given + element is found in the dependent array. + + + The `removedItem` and `addedItem` functions both have the following signature: + + ```javascript + function(accumulatedValue, item, changeMeta, instanceMeta) + ``` + + `accumulatedValue` - The value returned from the last time + `removedItem` or `addedItem` was called or an empty array. + + `item` - the element added or removed from the array + + `changeMeta` - An object which contains meta information about the + change. It contains the following properties: + + - `property` the computed property + - `propertyName` the name of the property on the object + - `index` the index of the added or removed item + - `item` the added or removed item: this is exactly the same as + the second arg + - `arrayChanged` the array that triggered the change. Can be + useful when depending on multiple arrays. + + For property changes triggered on an item property change (when + depKey is something like `someArray.@each.someProperty`), + `changeMeta` will also contain the following property: + + - `previousValues` an object whose keys are the properties that changed on + the item, and whose values are the item's previous values. + + `previousValues` is important Ember coalesces item property changes via + Ember.run.once. This means that by the time removedItem gets called, item has + the new values, but you may need the previous value (eg for sorting & + filtering). + + `instanceMeta` - An object that can be used to store meta + information needed for calculating your computed. For example a + unique computed might use this to store the number of times a given + element is found in the dependent array. + + The `removedItem` and `addedItem` functions should return the accumulated + value. It is acceptable to not return anything (ie return undefined) + to invalidate the computation. This is generally not a good idea for + arrayComputed but it's used in eg max and min. + + Example + + ```javascript + Ember.computed.map = function(dependentKey, callback) { + var options = { + addedItem: function(array, item, changeMeta, instanceMeta) { + var mapped = callback(item); + array.insertAt(changeMeta.index, mapped); + return array; + }, + removedItem: function(array, item, changeMeta, instanceMeta) { + array.removeAt(changeMeta.index, 1); + return array; + } + }; + + return Ember.arrayComputed(dependentKey, options); + }; + ``` + + @method arrayComputed + @for Ember + @param {String} [dependentKeys*] + @param {Object} options + @return {Ember.ComputedProperty} + */ + function arrayComputed (options) { + var args; + + if (arguments.length > 1) { + args = a_slice.call(arguments, 0, -1); + options = a_slice.call(arguments, -1)[0]; + } + + if (typeof options !== 'object') { + throw new EmberError('Array Computed Property declared without an options hash'); + } + + var cp = new ArrayComputedProperty(options); + + if (args) { + cp.property.apply(cp, args); + } + + return cp; + } + + __exports__.arrayComputed = arrayComputed; + __exports__.ArrayComputedProperty = ArrayComputedProperty; + }); +enifed("ember-runtime/computed/reduce_computed", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/error","ember-metal/property_events","ember-metal/expand_properties","ember-metal/observer","ember-metal/computed","ember-metal/platform","ember-metal/enumerable_utils","ember-runtime/system/tracked_array","ember-runtime/mixins/array","ember-metal/run_loop","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert + var e_get = __dependency2__.get; + var set = __dependency3__.set; + var guidFor = __dependency4__.guidFor; + var metaFor = __dependency4__.meta; + var EmberError = __dependency5__["default"]; + var propertyWillChange = __dependency6__.propertyWillChange; + var propertyDidChange = __dependency6__.propertyDidChange; + var expandProperties = __dependency7__["default"]; + var addObserver = __dependency8__.addObserver; + var observersFor = __dependency8__.observersFor; + var removeObserver = __dependency8__.removeObserver; + var addBeforeObserver = __dependency8__.addBeforeObserver; + var removeBeforeObserver = __dependency8__.removeBeforeObserver; + var ComputedProperty = __dependency9__.ComputedProperty; + var cacheFor = __dependency9__.cacheFor; + var o_create = __dependency10__.create; + var forEach = __dependency11__.forEach; + var TrackedArray = __dependency12__["default"]; + var EmberArray = __dependency13__["default"]; + var run = __dependency14__["default"]; + var isArray = __dependency4__.isArray; + + var cacheSet = cacheFor.set; + var cacheGet = cacheFor.get; + var cacheRemove = cacheFor.remove; + var a_slice = [].slice; + // Here we explicitly don't allow `@each.foo`; it would require some special + // testing, but there's no particular reason why it should be disallowed. + var eachPropertyPattern = /^(.*)\.@each\.(.*)/; + var doubleEachPropertyPattern = /(.*\.@each){2,}/; + var arrayBracketPattern = /\.\[\]$/; + + function get(obj, key) { + if (key === '@this') { + return obj; + } + + return e_get(obj, key); + } + + /* + Tracks changes to dependent arrays, as well as to properties of items in + dependent arrays. + + @class DependentArraysObserver + */ + function DependentArraysObserver(callbacks, cp, instanceMeta, context, propertyName, sugarMeta) { + // user specified callbacks for `addedItem` and `removedItem` + this.callbacks = callbacks; + + // the computed property: remember these are shared across instances + this.cp = cp; + + // the ReduceComputedPropertyInstanceMeta this DependentArraysObserver is + // associated with + this.instanceMeta = instanceMeta; + + // A map of array guids to dependentKeys, for the given context. We track + // this because we want to set up the computed property potentially before the + // dependent array even exists, but when the array observer fires, we lack + // enough context to know what to update: we can recover that context by + // getting the dependentKey. + this.dependentKeysByGuid = {}; + + // a map of dependent array guids -> TrackedArray instances. We use + // this to lazily recompute indexes for item property observers. + this.trackedArraysByGuid = {}; + + // We suspend observers to ignore replacements from `reset` when totally + // recomputing. Unfortunately we cannot properly suspend the observers + // because we only have the key; instead we make the observers no-ops + this.suspended = false; + + // This is used to coalesce item changes from property observers within a + // single item. + this.changedItems = {}; + // This is used to coalesce item changes for multiple items that depend on + // some shared state. + this.changedItemCount = 0; + } + + function ItemPropertyObserverContext (dependentArray, index, trackedArray) { + + this.dependentArray = dependentArray; + this.index = index; + this.item = dependentArray.objectAt(index); + this.trackedArray = trackedArray; + this.beforeObserver = null; + this.observer = null; + this.destroyed = false; + } + + DependentArraysObserver.prototype = { + setValue: function (newValue) { + this.instanceMeta.setValue(newValue, true); + }, + + getValue: function () { + return this.instanceMeta.getValue(); + }, + + setupObservers: function (dependentArray, dependentKey) { + this.dependentKeysByGuid[guidFor(dependentArray)] = dependentKey; + + dependentArray.addArrayObserver(this, { + willChange: 'dependentArrayWillChange', + didChange: 'dependentArrayDidChange' + }); + + if (this.cp._itemPropertyKeys[dependentKey]) { + this.setupPropertyObservers(dependentKey, this.cp._itemPropertyKeys[dependentKey]); + } + }, + + teardownObservers: function (dependentArray, dependentKey) { + var itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey] || []; + + delete this.dependentKeysByGuid[guidFor(dependentArray)]; + + this.teardownPropertyObservers(dependentKey, itemPropertyKeys); + + dependentArray.removeArrayObserver(this, { + willChange: 'dependentArrayWillChange', + didChange: 'dependentArrayDidChange' + }); + }, + + suspendArrayObservers: function (callback, binding) { + var oldSuspended = this.suspended; + this.suspended = true; + callback.call(binding); + this.suspended = oldSuspended; + }, + + setupPropertyObservers: function (dependentKey, itemPropertyKeys) { + var dependentArray = get(this.instanceMeta.context, dependentKey); + var length = get(dependentArray, 'length'); + var observerContexts = new Array(length); + + this.resetTransformations(dependentKey, observerContexts); + + forEach(dependentArray, function (item, index) { + var observerContext = this.createPropertyObserverContext(dependentArray, index, this.trackedArraysByGuid[dependentKey]); + observerContexts[index] = observerContext; + + forEach(itemPropertyKeys, function (propertyKey) { + addBeforeObserver(item, propertyKey, this, observerContext.beforeObserver); + addObserver(item, propertyKey, this, observerContext.observer); + }, this); + }, this); + }, + + teardownPropertyObservers: function (dependentKey, itemPropertyKeys) { + var dependentArrayObserver = this; + var trackedArray = this.trackedArraysByGuid[dependentKey]; + var beforeObserver, observer, item; + + if (!trackedArray) { return; } + + trackedArray.apply(function (observerContexts, offset, operation) { + if (operation === TrackedArray.DELETE) { return; } + + forEach(observerContexts, function (observerContext) { + observerContext.destroyed = true; + beforeObserver = observerContext.beforeObserver; + observer = observerContext.observer; + item = observerContext.item; + + forEach(itemPropertyKeys, function (propertyKey) { + removeBeforeObserver(item, propertyKey, dependentArrayObserver, beforeObserver); + removeObserver(item, propertyKey, dependentArrayObserver, observer); + }); + }); + }); + }, + + createPropertyObserverContext: function (dependentArray, index, trackedArray) { + var observerContext = new ItemPropertyObserverContext(dependentArray, index, trackedArray); + + this.createPropertyObserver(observerContext); + + return observerContext; + }, + + createPropertyObserver: function (observerContext) { + var dependentArrayObserver = this; + + observerContext.beforeObserver = function (obj, keyName) { + return dependentArrayObserver.itemPropertyWillChange(obj, keyName, observerContext.dependentArray, observerContext); + }; + + observerContext.observer = function (obj, keyName) { + return dependentArrayObserver.itemPropertyDidChange(obj, keyName, observerContext.dependentArray, observerContext); + }; + }, + + resetTransformations: function (dependentKey, observerContexts) { + this.trackedArraysByGuid[dependentKey] = new TrackedArray(observerContexts); + }, + + trackAdd: function (dependentKey, index, newItems) { + var trackedArray = this.trackedArraysByGuid[dependentKey]; + + if (trackedArray) { + trackedArray.addItems(index, newItems); + } + }, + + trackRemove: function (dependentKey, index, removedCount) { + var trackedArray = this.trackedArraysByGuid[dependentKey]; + + if (trackedArray) { + return trackedArray.removeItems(index, removedCount); + } + + return []; + }, + + updateIndexes: function (trackedArray, array) { + var length = get(array, 'length'); + // OPTIMIZE: we could stop updating once we hit the object whose observer + // fired; ie partially apply the transformations + trackedArray.apply(function (observerContexts, offset, operation, operationIndex) { + // we don't even have observer contexts for removed items, even if we did, + // they no longer have any index in the array + if (operation === TrackedArray.DELETE) { return; } + if (operationIndex === 0 && operation === TrackedArray.RETAIN && observerContexts.length === length && offset === 0) { + // If we update many items we don't want to walk the array each time: we + // only need to update the indexes at most once per run loop. + return; + } + + forEach(observerContexts, function (context, index) { + context.index = index + offset; + }); + }); + }, + + dependentArrayWillChange: function (dependentArray, index, removedCount, addedCount) { + if (this.suspended) { return; } + + var removedItem = this.callbacks.removedItem; + var changeMeta; + var guid = guidFor(dependentArray); + var dependentKey = this.dependentKeysByGuid[guid]; + var itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey] || []; + var length = get(dependentArray, 'length'); + var normalizedIndex = normalizeIndex(index, length, 0); + var normalizedRemoveCount = normalizeRemoveCount(normalizedIndex, length, removedCount); + var item, itemIndex, sliceIndex, observerContexts; + + observerContexts = this.trackRemove(dependentKey, normalizedIndex, normalizedRemoveCount); + + function removeObservers(propertyKey) { + observerContexts[sliceIndex].destroyed = true; + removeBeforeObserver(item, propertyKey, this, observerContexts[sliceIndex].beforeObserver); + removeObserver(item, propertyKey, this, observerContexts[sliceIndex].observer); + } + + for (sliceIndex = normalizedRemoveCount - 1; sliceIndex >= 0; --sliceIndex) { + itemIndex = normalizedIndex + sliceIndex; + if (itemIndex >= length) { break; } + + item = dependentArray.objectAt(itemIndex); + + forEach(itemPropertyKeys, removeObservers, this); + + changeMeta = new ChangeMeta(dependentArray, item, itemIndex, this.instanceMeta.propertyName, this.cp, normalizedRemoveCount); + this.setValue(removedItem.call( + this.instanceMeta.context, this.getValue(), item, changeMeta, this.instanceMeta.sugarMeta)); + } + this.callbacks.flushedChanges.call(this.instanceMeta.context, this.getValue(), this.instanceMeta.sugarMeta); + }, + + dependentArrayDidChange: function (dependentArray, index, removedCount, addedCount) { + if (this.suspended) { return; } + + var addedItem = this.callbacks.addedItem; + var guid = guidFor(dependentArray); + var dependentKey = this.dependentKeysByGuid[guid]; + var observerContexts = new Array(addedCount); + var itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey]; + var length = get(dependentArray, 'length'); + var normalizedIndex = normalizeIndex(index, length, addedCount); + var endIndex = normalizedIndex + addedCount; + var changeMeta, observerContext; + + forEach(dependentArray.slice(normalizedIndex, endIndex), function (item, sliceIndex) { + if (itemPropertyKeys) { + observerContext = this.createPropertyObserverContext(dependentArray, normalizedIndex + sliceIndex, + this.trackedArraysByGuid[dependentKey]); + observerContexts[sliceIndex] = observerContext; + + forEach(itemPropertyKeys, function (propertyKey) { + addBeforeObserver(item, propertyKey, this, observerContext.beforeObserver); + addObserver(item, propertyKey, this, observerContext.observer); + }, this); + } + + changeMeta = new ChangeMeta(dependentArray, item, normalizedIndex + sliceIndex, this.instanceMeta.propertyName, this.cp, addedCount); + this.setValue(addedItem.call( + this.instanceMeta.context, this.getValue(), item, changeMeta, this.instanceMeta.sugarMeta)); + }, this); + this.callbacks.flushedChanges.call(this.instanceMeta.context, this.getValue(), this.instanceMeta.sugarMeta); + this.trackAdd(dependentKey, normalizedIndex, observerContexts); + }, + + itemPropertyWillChange: function (obj, keyName, array, observerContext) { + var guid = guidFor(obj); + + if (!this.changedItems[guid]) { + this.changedItems[guid] = { + array: array, + observerContext: observerContext, + obj: obj, + previousValues: {} + }; + } + + ++this.changedItemCount; + this.changedItems[guid].previousValues[keyName] = get(obj, keyName); + }, + + itemPropertyDidChange: function (obj, keyName, array, observerContext) { + if (--this.changedItemCount === 0) { + this.flushChanges(); + } + }, + + flushChanges: function () { + var changedItems = this.changedItems; + var key, c, changeMeta; + + for (key in changedItems) { + c = changedItems[key]; + if (c.observerContext.destroyed) { continue; } + + this.updateIndexes(c.observerContext.trackedArray, c.observerContext.dependentArray); + + changeMeta = new ChangeMeta(c.array, c.obj, c.observerContext.index, this.instanceMeta.propertyName, this.cp, changedItems.length, c.previousValues); + this.setValue( + this.callbacks.removedItem.call(this.instanceMeta.context, this.getValue(), c.obj, changeMeta, this.instanceMeta.sugarMeta)); + this.setValue( + this.callbacks.addedItem.call(this.instanceMeta.context, this.getValue(), c.obj, changeMeta, this.instanceMeta.sugarMeta)); + } + + this.changedItems = {}; + this.callbacks.flushedChanges.call(this.instanceMeta.context, this.getValue(), this.instanceMeta.sugarMeta); + } + }; + + function normalizeIndex(index, length, newItemsOffset) { + if (index < 0) { + return Math.max(0, length + index); + } else if (index < length) { + return index; + } else /* index > length */ { + return Math.min(length - newItemsOffset, index); + } + } + + function normalizeRemoveCount(index, length, removedCount) { + return Math.min(removedCount, length - index); + } + + function ChangeMeta(dependentArray, item, index, propertyName, property, changedCount, previousValues){ + this.arrayChanged = dependentArray; + this.index = index; + this.item = item; + this.propertyName = propertyName; + this.property = property; + this.changedCount = changedCount; + + if (previousValues) { + // previous values only available for item property changes + this.previousValues = previousValues; + } + } + + function addItems(dependentArray, callbacks, cp, propertyName, meta) { + forEach(dependentArray, function (item, index) { + meta.setValue( callbacks.addedItem.call( + this, meta.getValue(), item, new ChangeMeta(dependentArray, item, index, propertyName, cp, dependentArray.length), meta.sugarMeta)); + }, this); + callbacks.flushedChanges.call(this, meta.getValue(), meta.sugarMeta); + } + + function reset(cp, propertyName) { + var callbacks = cp._callbacks(); + var hadMeta = cp._hasInstanceMeta(this, propertyName); + var meta = cp._instanceMeta(this, propertyName); + + if (hadMeta) { meta.setValue(cp.resetValue(meta.getValue())); } + + if (cp.options.initialize) { + cp.options.initialize.call(this, meta.getValue(), { + property: cp, + propertyName: propertyName + }, meta.sugarMeta); + } + } + + function partiallyRecomputeFor(obj, dependentKey) { + if (arrayBracketPattern.test(dependentKey)) { + return false; + } + + var value = get(obj, dependentKey); + return EmberArray.detect(value); + } + + function ReduceComputedPropertyInstanceMeta(context, propertyName, initialValue) { + this.context = context; + this.propertyName = propertyName; + this.cache = metaFor(context).cache; + this.dependentArrays = {}; + this.sugarMeta = {}; + this.initialValue = initialValue; + } + + ReduceComputedPropertyInstanceMeta.prototype = { + getValue: function () { + var value = cacheGet(this.cache, this.propertyName); + + if (value !== undefined) { + return value; + } else { + return this.initialValue; + } + }, + + setValue: function(newValue, triggerObservers) { + // This lets sugars force a recomputation, handy for very simple + // implementations of eg max. + if (newValue === cacheGet(this.cache, this.propertyName)) { + return; + } + + if (triggerObservers) { + propertyWillChange(this.context, this.propertyName); + } + + if (newValue === undefined) { + cacheRemove(this.cache, this.propertyName); + } else { + cacheSet(this.cache, this.propertyName, newValue); + } + + if (triggerObservers) { + propertyDidChange(this.context, this.propertyName); + } + } + }; + + /** + A computed property whose dependent keys are arrays and which is updated with + "one at a time" semantics. + + @class ReduceComputedProperty + @namespace Ember + @extends Ember.ComputedProperty + @constructor + */ + + __exports__.ReduceComputedProperty = ReduceComputedProperty; + // TODO: default export + + function ReduceComputedProperty(options) { + var cp = this; + + this.options = options; + this._dependentKeys = null; + // A map of dependentKey -> [itemProperty, ...] that tracks what properties of + // items in the array we must track to update this property. + this._itemPropertyKeys = {}; + this._previousItemPropertyKeys = {}; + + this.readOnly(); + this.cacheable(); + + this.recomputeOnce = function(propertyName) { + // What we really want to do is coalesce by . + // We need a form of `scheduleOnce` that accepts an arbitrary token to + // coalesce by, in addition to the target and method. + run.once(this, recompute, propertyName); + }; + + var recompute = function(propertyName) { + var dependentKeys = cp._dependentKeys; + var meta = cp._instanceMeta(this, propertyName); + var callbacks = cp._callbacks(); + + reset.call(this, cp, propertyName); + + meta.dependentArraysObserver.suspendArrayObservers(function () { + forEach(cp._dependentKeys, function (dependentKey) { + + if (!partiallyRecomputeFor(this, dependentKey)) { return; } + + var dependentArray = get(this, dependentKey); + var previousDependentArray = meta.dependentArrays[dependentKey]; + + if (dependentArray === previousDependentArray) { + // The array may be the same, but our item property keys may have + // changed, so we set them up again. We can't easily tell if they've + // changed: the array may be the same object, but with different + // contents. + if (cp._previousItemPropertyKeys[dependentKey]) { + delete cp._previousItemPropertyKeys[dependentKey]; + meta.dependentArraysObserver.setupPropertyObservers(dependentKey, cp._itemPropertyKeys[dependentKey]); + } + } else { + meta.dependentArrays[dependentKey] = dependentArray; + + if (previousDependentArray) { + meta.dependentArraysObserver.teardownObservers(previousDependentArray, dependentKey); + } + + if (dependentArray) { + meta.dependentArraysObserver.setupObservers(dependentArray, dependentKey); + } + } + }, this); + }, this); + + forEach(cp._dependentKeys, function(dependentKey) { + if (!partiallyRecomputeFor(this, dependentKey)) { return; } + + var dependentArray = get(this, dependentKey); + + if (dependentArray) { + addItems.call(this, dependentArray, callbacks, cp, propertyName, meta); + } + }, this); + }; + + + this.func = function (propertyName) { + + recompute.call(this, propertyName); + + return cp._instanceMeta(this, propertyName).getValue(); + }; + } + + ReduceComputedProperty.prototype = o_create(ComputedProperty.prototype); + + function defaultCallback(computedValue) { + return computedValue; + } + + ReduceComputedProperty.prototype._callbacks = function () { + if (!this.callbacks) { + var options = this.options; + + this.callbacks = { + removedItem: options.removedItem || defaultCallback, + addedItem: options.addedItem || defaultCallback, + flushedChanges: options.flushedChanges || defaultCallback + }; + } + + return this.callbacks; + }; + + ReduceComputedProperty.prototype._hasInstanceMeta = function (context, propertyName) { + return !!metaFor(context).cacheMeta[propertyName]; + }; + + ReduceComputedProperty.prototype._instanceMeta = function (context, propertyName) { + var cacheMeta = metaFor(context).cacheMeta; + var meta = cacheMeta[propertyName]; + + if (!meta) { + meta = cacheMeta[propertyName] = new ReduceComputedPropertyInstanceMeta(context, propertyName, this.initialValue()); + meta.dependentArraysObserver = new DependentArraysObserver(this._callbacks(), this, meta, context, propertyName, meta.sugarMeta); + } + + return meta; + }; + + ReduceComputedProperty.prototype.initialValue = function () { + if (typeof this.options.initialValue === 'function') { + return this.options.initialValue(); + } + else { + return this.options.initialValue; + } + }; + + ReduceComputedProperty.prototype.resetValue = function (value) { + return this.initialValue(); + }; + + ReduceComputedProperty.prototype.itemPropertyKey = function (dependentArrayKey, itemPropertyKey) { + this._itemPropertyKeys[dependentArrayKey] = this._itemPropertyKeys[dependentArrayKey] || []; + this._itemPropertyKeys[dependentArrayKey].push(itemPropertyKey); + }; + + ReduceComputedProperty.prototype.clearItemPropertyKeys = function (dependentArrayKey) { + if (this._itemPropertyKeys[dependentArrayKey]) { + this._previousItemPropertyKeys[dependentArrayKey] = this._itemPropertyKeys[dependentArrayKey]; + this._itemPropertyKeys[dependentArrayKey] = []; + } + }; + + ReduceComputedProperty.prototype.property = function () { + var cp = this; + var args = a_slice.call(arguments); + var propertyArgs = {}; + var match, dependentArrayKey, itemPropertyKey; + + forEach(args, function (dependentKey) { + if (doubleEachPropertyPattern.test(dependentKey)) { + throw new EmberError('Nested @each properties not supported: ' + dependentKey); + } else if (match = eachPropertyPattern.exec(dependentKey)) { + dependentArrayKey = match[1]; + + var itemPropertyKeyPattern = match[2]; + var addItemPropertyKey = function (itemPropertyKey) { + cp.itemPropertyKey(dependentArrayKey, itemPropertyKey); + }; + + expandProperties(itemPropertyKeyPattern, addItemPropertyKey); + propertyArgs[guidFor(dependentArrayKey)] = dependentArrayKey; + } else { + propertyArgs[guidFor(dependentKey)] = dependentKey; + } + }); + + var propertyArgsToArray = []; + for (var guid in propertyArgs) { + propertyArgsToArray.push(propertyArgs[guid]); + } + + return ComputedProperty.prototype.property.apply(this, propertyArgsToArray); + }; + + /** + Creates a computed property which operates on dependent arrays and + is updated with "one at a time" semantics. When items are added or + removed from the dependent array(s) a reduce computed only operates + on the change instead of re-evaluating the entire array. + + If there are more than one arguments the first arguments are + considered to be dependent property keys. The last argument is + required to be an options object. The options object can have the + following four properties: + + `initialValue` - A value or function that will be used as the initial + value for the computed. If this property is a function the result of calling + the function will be used as the initial value. This property is required. + + `initialize` - An optional initialize function. Typically this will be used + to set up state on the instanceMeta object. + + `removedItem` - A function that is called each time an element is removed + from the array. + + `addedItem` - A function that is called each time an element is added to + the array. + + + The `initialize` function has the following signature: + + ```javascript + function(initialValue, changeMeta, instanceMeta) + ``` + + `initialValue` - The value of the `initialValue` property from the + options object. + + `changeMeta` - An object which contains meta information about the + computed. It contains the following properties: + + - `property` the computed property + - `propertyName` the name of the property on the object + + `instanceMeta` - An object that can be used to store meta + information needed for calculating your computed. For example a + unique computed might use this to store the number of times a given + element is found in the dependent array. + + + The `removedItem` and `addedItem` functions both have the following signature: + + ```javascript + function(accumulatedValue, item, changeMeta, instanceMeta) + ``` + + `accumulatedValue` - The value returned from the last time + `removedItem` or `addedItem` was called or `initialValue`. + + `item` - the element added or removed from the array + + `changeMeta` - An object which contains meta information about the + change. It contains the following properties: + + - `property` the computed property + - `propertyName` the name of the property on the object + - `index` the index of the added or removed item + - `item` the added or removed item: this is exactly the same as + the second arg + - `arrayChanged` the array that triggered the change. Can be + useful when depending on multiple arrays. + + For property changes triggered on an item property change (when + depKey is something like `someArray.@each.someProperty`), + `changeMeta` will also contain the following property: + + - `previousValues` an object whose keys are the properties that changed on + the item, and whose values are the item's previous values. + + `previousValues` is important Ember coalesces item property changes via + Ember.run.once. This means that by the time removedItem gets called, item has + the new values, but you may need the previous value (eg for sorting & + filtering). + + `instanceMeta` - An object that can be used to store meta + information needed for calculating your computed. For example a + unique computed might use this to store the number of times a given + element is found in the dependent array. + + The `removedItem` and `addedItem` functions should return the accumulated + value. It is acceptable to not return anything (ie return undefined) + to invalidate the computation. This is generally not a good idea for + arrayComputed but it's used in eg max and min. + + Note that observers will be fired if either of these functions return a value + that differs from the accumulated value. When returning an object that + mutates in response to array changes, for example an array that maps + everything from some other array (see `Ember.computed.map`), it is usually + important that the *same* array be returned to avoid accidentally triggering observers. + + Example + + ```javascript + Ember.computed.max = function(dependentKey) { + return Ember.reduceComputed(dependentKey, { + initialValue: -Infinity, + + addedItem: function(accumulatedValue, item, changeMeta, instanceMeta) { + return Math.max(accumulatedValue, item); + }, + + removedItem: function(accumulatedValue, item, changeMeta, instanceMeta) { + if (item < accumulatedValue) { + return accumulatedValue; + } + } + }); + }; + ``` + + Dependent keys may refer to `@this` to observe changes to the object itself, + which must be array-like, rather than a property of the object. This is + mostly useful for array proxies, to ensure objects are retrieved via + `objectAtContent`. This is how you could sort items by properties defined on an item controller. + + Example + + ```javascript + App.PeopleController = Ember.ArrayController.extend({ + itemController: 'person', + + sortedPeople: Ember.computed.sort('@this.@each.reversedName', function(personA, personB) { + // `reversedName` isn't defined on Person, but we have access to it via + // the item controller App.PersonController. If we'd used + // `content.@each.reversedName` above, we would be getting the objects + // directly and not have access to `reversedName`. + // + var reversedNameA = get(personA, 'reversedName'); + var reversedNameB = get(personB, 'reversedName'); + + return Ember.compare(reversedNameA, reversedNameB); + }) + }); + + App.PersonController = Ember.ObjectController.extend({ + reversedName: function() { + return reverse(get(this, 'name')); + }.property('name') + }); + ``` + + Dependent keys whose values are not arrays are treated as regular + dependencies: when they change, the computed property is completely + recalculated. It is sometimes useful to have dependent arrays with similar + semantics. Dependent keys which end in `.[]` do not use "one at a time" + semantics. When an item is added or removed from such a dependency, the + computed property is completely recomputed. + + When the computed property is completely recomputed, the `accumulatedValue` + is discarded, it starts with `initialValue` again, and each item is passed + to `addedItem` in turn. + + Example + + ```javascript + Ember.Object.extend({ + // When `string` is changed, `computed` is completely recomputed. + string: 'a string', + + // When an item is added to `array`, `addedItem` is called. + array: [], + + // When an item is added to `anotherArray`, `computed` is completely + // recomputed. + anotherArray: [], + + computed: Ember.reduceComputed('string', 'array', 'anotherArray.[]', { + addedItem: addedItemCallback, + removedItem: removedItemCallback + }) + }); + ``` + + @method reduceComputed + @for Ember + @param {String} [dependentKeys*] + @param {Object} options + @return {Ember.ComputedProperty} + */ + function reduceComputed(options) { + var args; + + if (arguments.length > 1) { + args = a_slice.call(arguments, 0, -1); + options = a_slice.call(arguments, -1)[0]; + } + + if (typeof options !== 'object') { + throw new EmberError('Reduce Computed Property declared without an options hash'); + } + + if (!('initialValue' in options)) { + throw new EmberError('Reduce Computed Property declared without an initial value'); + } + + var cp = new ReduceComputedProperty(options); + + if (args) { + cp.property.apply(cp, args); + } + + return cp; + } + + __exports__.reduceComputed = reduceComputed; + }); +enifed("ember-runtime/computed/reduce_computed_macros", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/error","ember-metal/enumerable_utils","ember-metal/run_loop","ember-metal/observer","ember-runtime/computed/array_computed","ember-runtime/computed/reduce_computed","ember-runtime/system/subarray","ember-metal/keys","ember-runtime/compare","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + // Ember.assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var isArray = __dependency4__.isArray; + var guidFor = __dependency4__.guidFor; + var EmberError = __dependency5__["default"]; + var forEach = __dependency6__.forEach; + var run = __dependency7__["default"]; + var addObserver = __dependency8__.addObserver; + var arrayComputed = __dependency9__.arrayComputed; + var reduceComputed = __dependency10__.reduceComputed; + var SubArray = __dependency11__["default"]; + var keys = __dependency12__["default"]; + var compare = __dependency13__["default"]; + + var a_slice = [].slice; + + /** + A computed property that returns the sum of the value + in the dependent array. + + @method computed.sum + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computes the sum of all values in the dependentKey's array + @since 1.4.0 + */ + + function sum(dependentKey){ + return reduceComputed(dependentKey, { + initialValue: 0, + + addedItem: function(accumulatedValue, item, changeMeta, instanceMeta){ + return accumulatedValue + item; + }, + + removedItem: function(accumulatedValue, item, changeMeta, instanceMeta){ + return accumulatedValue - item; + } + }); + } + + __exports__.sum = sum;/** + A computed property that calculates the maximum value in the + dependent array. This will return `-Infinity` when the dependent + array is empty. + + ```javascript + var Person = Ember.Object.extend({ + childAges: Ember.computed.mapBy('children', 'age'), + maxChildAge: Ember.computed.max('childAges') + }); + + var lordByron = Person.create({ children: [] }); + + lordByron.get('maxChildAge'); // -Infinity + lordByron.get('children').pushObject({ + name: 'Augusta Ada Byron', age: 7 + }); + lordByron.get('maxChildAge'); // 7 + lordByron.get('children').pushObjects([{ + name: 'Allegra Byron', + age: 5 + }, { + name: 'Elizabeth Medora Leigh', + age: 8 + }]); + lordByron.get('maxChildAge'); // 8 + ``` + + @method computed.max + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computes the largest value in the dependentKey's array + */ + function max(dependentKey) { + return reduceComputed(dependentKey, { + initialValue: -Infinity, + + addedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { + return Math.max(accumulatedValue, item); + }, + + removedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { + if (item < accumulatedValue) { + return accumulatedValue; + } + } + }); + } + + __exports__.max = max;/** + A computed property that calculates the minimum value in the + dependent array. This will return `Infinity` when the dependent + array is empty. + + ```javascript + var Person = Ember.Object.extend({ + childAges: Ember.computed.mapBy('children', 'age'), + minChildAge: Ember.computed.min('childAges') + }); + + var lordByron = Person.create({ children: [] }); + + lordByron.get('minChildAge'); // Infinity + lordByron.get('children').pushObject({ + name: 'Augusta Ada Byron', age: 7 + }); + lordByron.get('minChildAge'); // 7 + lordByron.get('children').pushObjects([{ + name: 'Allegra Byron', + age: 5 + }, { + name: 'Elizabeth Medora Leigh', + age: 8 + }]); + lordByron.get('minChildAge'); // 5 + ``` + + @method computed.min + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computes the smallest value in the dependentKey's array + */ + function min(dependentKey) { + return reduceComputed(dependentKey, { + initialValue: Infinity, + + addedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { + return Math.min(accumulatedValue, item); + }, + + removedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { + if (item > accumulatedValue) { + return accumulatedValue; + } + } + }); + } + + __exports__.min = min;/** + Returns an array mapped via the callback + + The callback method you provide should have the following signature. + `item` is the current item in the iteration. + `index` is the integer index of the current item in the iteration. + + ```javascript + function(item, index); + ``` + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + excitingChores: Ember.computed.map('chores', function(chore, index) { + return chore.toUpperCase() + '!'; + }) + }); + + var hamster = Hamster.create({ + chores: ['clean', 'write more unit tests'] + }); + + hamster.get('excitingChores'); // ['CLEAN!', 'WRITE MORE UNIT TESTS!'] + ``` + + @method computed.map + @for Ember + @param {String} dependentKey + @param {Function} callback + @return {Ember.ComputedProperty} an array mapped via the callback + */ + function map(dependentKey, callback) { + var options = { + addedItem: function(array, item, changeMeta, instanceMeta) { + var mapped = callback.call(this, item, changeMeta.index); + array.insertAt(changeMeta.index, mapped); + return array; + }, + removedItem: function(array, item, changeMeta, instanceMeta) { + array.removeAt(changeMeta.index, 1); + return array; + } + }; + + return arrayComputed(dependentKey, options); + } + + __exports__.map = map;/** + Returns an array mapped to the specified key. + + ```javascript + var Person = Ember.Object.extend({ + childAges: Ember.computed.mapBy('children', 'age') + }); + + var lordByron = Person.create({ children: [] }); + + lordByron.get('childAges'); // [] + lordByron.get('children').pushObject({ name: 'Augusta Ada Byron', age: 7 }); + lordByron.get('childAges'); // [7] + lordByron.get('children').pushObjects([{ + name: 'Allegra Byron', + age: 5 + }, { + name: 'Elizabeth Medora Leigh', + age: 8 + }]); + lordByron.get('childAges'); // [7, 5, 8] + ``` + + @method computed.mapBy + @for Ember + @param {String} dependentKey + @param {String} propertyKey + @return {Ember.ComputedProperty} an array mapped to the specified key + */ + function mapBy (dependentKey, propertyKey) { + var callback = function(item) { return get(item, propertyKey); }; + return map(dependentKey + '.@each.' + propertyKey, callback); + } + + __exports__.mapBy = mapBy;/** + @method computed.mapProperty + @for Ember + @deprecated Use `Ember.computed.mapBy` instead + @param dependentKey + @param propertyKey + */ + var mapProperty = mapBy; + __exports__.mapProperty = mapProperty; + /** + Filters the array by the callback. + + The callback method you provide should have the following signature. + `item` is the current item in the iteration. + `index` is the integer index of the current item in the iteration. + + ```javascript + function(item, index); + ``` + + ```javascript + var Hamster = Ember.Object.extend({ + remainingChores: Ember.computed.filter('chores', function(chore, index) { + return !chore.done; + }) + }); + + var hamster = Hamster.create({ + chores: [ + { name: 'cook', done: true }, + { name: 'clean', done: true }, + { name: 'write more unit tests', done: false } + ] + }); + + hamster.get('remainingChores'); // [{name: 'write more unit tests', done: false}] + ``` + + @method computed.filter + @for Ember + @param {String} dependentKey + @param {Function} callback + @return {Ember.ComputedProperty} the filtered array + */ + function filter(dependentKey, callback) { + var options = { + initialize: function (array, changeMeta, instanceMeta) { + instanceMeta.filteredArrayIndexes = new SubArray(); + }, + + addedItem: function (array, item, changeMeta, instanceMeta) { + var match = !!callback.call(this, item, changeMeta.index); + var filterIndex = instanceMeta.filteredArrayIndexes.addItem(changeMeta.index, match); + + if (match) { + array.insertAt(filterIndex, item); + } + + return array; + }, + + removedItem: function(array, item, changeMeta, instanceMeta) { + var filterIndex = instanceMeta.filteredArrayIndexes.removeItem(changeMeta.index); + + if (filterIndex > -1) { + array.removeAt(filterIndex); + } + + return array; + } + }; + + return arrayComputed(dependentKey, options); + } + + __exports__.filter = filter;/** + Filters the array by the property and value + + ```javascript + var Hamster = Ember.Object.extend({ + remainingChores: Ember.computed.filterBy('chores', 'done', false) + }); + + var hamster = Hamster.create({ + chores: [ + { name: 'cook', done: true }, + { name: 'clean', done: true }, + { name: 'write more unit tests', done: false } + ] + }); + + hamster.get('remainingChores'); // [{ name: 'write more unit tests', done: false }] + ``` + + @method computed.filterBy + @for Ember + @param {String} dependentKey + @param {String} propertyKey + @param {*} value + @return {Ember.ComputedProperty} the filtered array + */ + function filterBy (dependentKey, propertyKey, value) { + var callback; + + if (arguments.length === 2) { + callback = function(item) { + return get(item, propertyKey); + }; + } else { + callback = function(item) { + return get(item, propertyKey) === value; + }; + } + + return filter(dependentKey + '.@each.' + propertyKey, callback); + } + + __exports__.filterBy = filterBy;/** + @method computed.filterProperty + @for Ember + @param dependentKey + @param propertyKey + @param value + @deprecated Use `Ember.computed.filterBy` instead + */ + var filterProperty = filterBy; + __exports__.filterProperty = filterProperty; + /** + A computed property which returns a new array with all the unique + elements from one or more dependent arrays. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + uniqueFruits: Ember.computed.uniq('fruits') + }); + + var hamster = Hamster.create({ + fruits: [ + 'banana', + 'grape', + 'kale', + 'banana' + ] + }); + + hamster.get('uniqueFruits'); // ['banana', 'grape', 'kale'] + ``` + + @method computed.uniq + @for Ember + @param {String} propertyKey* + @return {Ember.ComputedProperty} computes a new array with all the + unique elements from the dependent array + */ + function uniq() { + var args = a_slice.call(arguments); + + args.push({ + initialize: function(array, changeMeta, instanceMeta) { + instanceMeta.itemCounts = {}; + }, + + addedItem: function(array, item, changeMeta, instanceMeta) { + var guid = guidFor(item); + + if (!instanceMeta.itemCounts[guid]) { + instanceMeta.itemCounts[guid] = 1; + array.pushObject(item); + } else { + ++instanceMeta.itemCounts[guid]; + } + return array; + }, + + removedItem: function(array, item, _, instanceMeta) { + var guid = guidFor(item); + var itemCounts = instanceMeta.itemCounts; + + if (--itemCounts[guid] === 0) { + array.removeObject(item); + } + + return array; + } + }); + + return arrayComputed.apply(null, args); + } + + __exports__.uniq = uniq;/** + Alias for [Ember.computed.uniq](/api/#method_computed_uniq). + + @method computed.union + @for Ember + @param {String} propertyKey* + @return {Ember.ComputedProperty} computes a new array with all the + unique elements from the dependent array + */ + var union = uniq; + __exports__.union = union; + /** + A computed property which returns a new array with all the duplicated + elements from two or more dependent arrays. + + Example + + ```javascript + var obj = Ember.Object.createWithMixins({ + adaFriends: ['Charles Babbage', 'John Hobhouse', 'William King', 'Mary Somerville'], + charlesFriends: ['William King', 'Mary Somerville', 'Ada Lovelace', 'George Peacock'], + friendsInCommon: Ember.computed.intersect('adaFriends', 'charlesFriends') + }); + + obj.get('friendsInCommon'); // ['William King', 'Mary Somerville'] + ``` + + @method computed.intersect + @for Ember + @param {String} propertyKey* + @return {Ember.ComputedProperty} computes a new array with all the + duplicated elements from the dependent arrays + */ + function intersect() { + var args = a_slice.call(arguments); + + args.push({ + initialize: function (array, changeMeta, instanceMeta) { + instanceMeta.itemCounts = {}; + }, + + addedItem: function(array, item, changeMeta, instanceMeta) { + var itemGuid = guidFor(item); + var dependentGuid = guidFor(changeMeta.arrayChanged); + var numberOfDependentArrays = changeMeta.property._dependentKeys.length; + var itemCounts = instanceMeta.itemCounts; + + if (!itemCounts[itemGuid]) { + itemCounts[itemGuid] = {}; + } + + if (itemCounts[itemGuid][dependentGuid] === undefined) { + itemCounts[itemGuid][dependentGuid] = 0; + } + + if (++itemCounts[itemGuid][dependentGuid] === 1 && + numberOfDependentArrays === keys(itemCounts[itemGuid]).length) { + array.addObject(item); + } + + return array; + }, + + removedItem: function(array, item, changeMeta, instanceMeta) { + var itemGuid = guidFor(item); + var dependentGuid = guidFor(changeMeta.arrayChanged); + var numberOfDependentArrays = changeMeta.property._dependentKeys.length; + var numberOfArraysItemAppearsIn; + var itemCounts = instanceMeta.itemCounts; + + if (itemCounts[itemGuid][dependentGuid] === undefined) { + itemCounts[itemGuid][dependentGuid] = 0; + } + + if (--itemCounts[itemGuid][dependentGuid] === 0) { + delete itemCounts[itemGuid][dependentGuid]; + numberOfArraysItemAppearsIn = keys(itemCounts[itemGuid]).length; + + if (numberOfArraysItemAppearsIn === 0) { + delete itemCounts[itemGuid]; + } + + array.removeObject(item); + } + + return array; + } + }); + + return arrayComputed.apply(null, args); + } + + __exports__.intersect = intersect;/** + A computed property which returns a new array with all the + properties from the first dependent array that are not in the second + dependent array. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + likes: ['banana', 'grape', 'kale'], + wants: Ember.computed.setDiff('likes', 'fruits') + }); + + var hamster = Hamster.create({ + fruits: [ + 'grape', + 'kale', + ] + }); + + hamster.get('wants'); // ['banana'] + ``` + + @method computed.setDiff + @for Ember + @param {String} setAProperty + @param {String} setBProperty + @return {Ember.ComputedProperty} computes a new array with all the + items from the first dependent array that are not in the second + dependent array + */ + function setDiff(setAProperty, setBProperty) { + if (arguments.length !== 2) { + throw new EmberError('setDiff requires exactly two dependent arrays.'); + } + + return arrayComputed(setAProperty, setBProperty, { + addedItem: function (array, item, changeMeta, instanceMeta) { + var setA = get(this, setAProperty); + var setB = get(this, setBProperty); + + if (changeMeta.arrayChanged === setA) { + if (!setB.contains(item)) { + array.addObject(item); + } + } else { + array.removeObject(item); + } + + return array; + }, + + removedItem: function (array, item, changeMeta, instanceMeta) { + var setA = get(this, setAProperty); + var setB = get(this, setBProperty); + + if (changeMeta.arrayChanged === setB) { + if (setA.contains(item)) { + array.addObject(item); + } + } else { + array.removeObject(item); + } + + return array; + } + }); + } + + __exports__.setDiff = setDiff;function binarySearch(array, item, low, high) { + var mid, midItem, res, guidMid, guidItem; + + if (arguments.length < 4) { + high = get(array, 'length'); + } + + if (arguments.length < 3) { + low = 0; + } + + if (low === high) { + return low; + } + + mid = low + Math.floor((high - low) / 2); + midItem = array.objectAt(mid); + + guidMid = guidFor(midItem); + guidItem = guidFor(item); + + if (guidMid === guidItem) { + return mid; + } + + res = this.order(midItem, item); + + if (res === 0) { + res = guidMid < guidItem ? -1 : 1; + } + + + if (res < 0) { + return this.binarySearch(array, item, mid+1, high); + } else if (res > 0) { + return this.binarySearch(array, item, low, mid); + } + + return mid; + } + + + /** + A computed property which returns a new array with all the + properties from the first dependent array sorted based on a property + or sort function. + + The callback method you provide should have the following signature: + + ```javascript + function(itemA, itemB); + ``` + + - `itemA` the first item to compare. + - `itemB` the second item to compare. + + This function should return negative number (e.g. `-1`) when `itemA` should come before + `itemB`. It should return positive number (e.g. `1`) when `itemA` should come after + `itemB`. If the `itemA` and `itemB` are equal this function should return `0`. + + Therefore, if this function is comparing some numeric values, simple `itemA - itemB` or + `itemA.get( 'foo' ) - itemB.get( 'foo' )` can be used instead of series of `if`. + + Example + + ```javascript + var ToDoList = Ember.Object.extend({ + // using standard ascending sort + todosSorting: ['name'], + sortedTodos: Ember.computed.sort('todos', 'todosSorting'), + + // using descending sort + todosSortingDesc: ['name:desc'], + sortedTodosDesc: Ember.computed.sort('todos', 'todosSortingDesc'), + + // using a custom sort function + priorityTodos: Ember.computed.sort('todos', function(a, b){ + if (a.priority > b.priority) { + return 1; + } else if (a.priority < b.priority) { + return -1; + } + + return 0; + }) + }); + + var todoList = ToDoList.create({todos: [ + { name: 'Unit Test', priority: 2 }, + { name: 'Documentation', priority: 3 }, + { name: 'Release', priority: 1 } + ]}); + + todoList.get('sortedTodos'); // [{ name:'Documentation', priority:3 }, { name:'Release', priority:1 }, { name:'Unit Test', priority:2 }] + todoList.get('sortedTodosDesc'); // [{ name:'Unit Test', priority:2 }, { name:'Release', priority:1 }, { name:'Documentation', priority:3 }] + todoList.get('priorityTodos'); // [{ name:'Release', priority:1 }, { name:'Unit Test', priority:2 }, { name:'Documentation', priority:3 }] + ``` + + @method computed.sort + @for Ember + @param {String} dependentKey + @param {String or Function} sortDefinition a dependent key to an + array of sort properties (add `:desc` to the arrays sort properties to sort descending) or a function to use when sorting + @return {Ember.ComputedProperty} computes a new sorted array based + on the sort property array or callback function + */ + function sort(itemsKey, sortDefinition) { + + if (typeof sortDefinition === 'function') { + return customSort(itemsKey, sortDefinition); + } else { + return propertySort(itemsKey, sortDefinition); + } + } + + __exports__.sort = sort;function customSort(itemsKey, comparator) { + return arrayComputed(itemsKey, { + initialize: function (array, changeMeta, instanceMeta) { + instanceMeta.order = comparator; + instanceMeta.binarySearch = binarySearch; + instanceMeta.waitingInsertions = []; + instanceMeta.insertWaiting = function() { + var index, item; + var waiting = instanceMeta.waitingInsertions; + instanceMeta.waitingInsertions = []; + for (var i=0; i{{post.title}} ({{post.titleLength}} characters) + {{/each}} + ``` + + ```javascript + App.PostsController = Ember.ArrayController.extend({ + itemController: 'post' + }); + + App.PostController = Ember.ObjectController.extend({ + // the `title` property will be proxied to the underlying post. + titleLength: function() { + return this.get('title').length; + }.property('title') + }); + ``` + + In some cases it is helpful to return a different `itemController` depending + on the particular item. Subclasses can do this by overriding + `lookupItemController`. + + For example: + + ```javascript + App.MyArrayController = Ember.ArrayController.extend({ + lookupItemController: function( object ) { + if (object.get('isSpecial')) { + return "special"; // use App.SpecialController + } else { + return "regular"; // use App.RegularController + } + } + }); + ``` + + The itemController instances will have a `parentController` property set to + the `ArrayController` instance. + + @class ArrayController + @namespace Ember + @extends Ember.ArrayProxy + @uses Ember.SortableMixin + @uses Ember.ControllerMixin + */ + + __exports__["default"] = ArrayProxy.extend(ControllerMixin, SortableMixin, { + + /** + The controller used to wrap items, if any. If the value is a string, it will + be used to lookup the container for the controller. As an alternative, you + can also provide a controller class as the value. + + For example: + + ```javascript + App.MyArrayController = Ember.ArrayController.extend({ + itemController: Ember.ObjectController.extend({ + //Item Controller Implementation + }) + }); + ``` + + @property itemController + @type String | Ember.Controller + @default null + */ + itemController: null, + + /** + Return the name of the controller to wrap items, or `null` if items should + be returned directly. The default implementation simply returns the + `itemController` property, but subclasses can override this method to return + different controllers for different objects. + + For example: + + ```javascript + App.MyArrayController = Ember.ArrayController.extend({ + lookupItemController: function( object ) { + if (object.get('isSpecial')) { + return "special"; // use App.SpecialController + } else { + return "regular"; // use App.RegularController + } + } + }); + ``` + + @method lookupItemController + @param {Object} object + @return {String} + */ + lookupItemController: function(object) { + return get(this, 'itemController'); + }, + + objectAtContent: function(idx) { + var length = get(this, 'length'); + var arrangedContent = get(this, 'arrangedContent'); + var object = arrangedContent && arrangedContent.objectAt(idx); + var controllerClass; + + if (idx >= 0 && idx < length) { + controllerClass = this.lookupItemController(object); + + if (controllerClass) { + return this.controllerAt(idx, object, controllerClass); + } + } + + // When `controllerClass` is falsy, we have not opted in to using item + // controllers, so return the object directly. + + // When the index is out of range, we want to return the "out of range" + // value, whatever that might be. Rather than make assumptions + // (e.g. guessing `null` or `undefined`) we defer this to `arrangedContent`. + return object; + }, + + arrangedContentDidChange: function() { + this._super(); + this._resetSubControllers(); + }, + + arrayContentDidChange: function(idx, removedCnt, addedCnt) { + var subControllers = this._subControllers; + + if (subControllers.length) { + var subControllersToRemove = subControllers.slice(idx, idx + removedCnt); + + forEach(subControllersToRemove, function(subController) { + if (subController) { + subController.destroy(); + } + }); + + replace(subControllers, idx, removedCnt, new Array(addedCnt)); + } + + // The shadow array of subcontrollers must be updated before we trigger + // observers, otherwise observers will get the wrong subcontainer when + // calling `objectAt` + this._super(idx, removedCnt, addedCnt); + }, + + init: function() { + this._super(); + this._subControllers = []; + }, + + model: computed(function () { + return Ember.A(); + }), + + /** + * Flag to mark as being "virtual". Used to keep this instance + * from participating in the parentController hierarchy. + * + * @private + * @property _isVirtual + * @type Boolean + */ + _isVirtual: false, + + controllerAt: function(idx, object, controllerClass) { + var container = get(this, 'container'); + var subControllers = this._subControllers; + var fullName, subController, subControllerFactory, parentController, options; + + if (subControllers.length > idx) { + subController = subControllers[idx]; + + if (subController) { + return subController; + } + } + + if (this._isVirtual) { + parentController = get(this, 'parentController'); + } else { + parentController = this; + } + + + fullName = 'controller:' + controllerClass; + + if (!container.has(fullName)) { + throw new EmberError('Could not resolve itemController: "' + controllerClass + '"'); + } + + subController = container.lookupFactory(fullName).create({ + target: parentController, + parentController: parentController, + model: object + }); + + + subControllers[idx] = subController; + + return subController; + }, + + _subControllers: null, + + _resetSubControllers: function() { + var controller; + var subControllers = this._subControllers; + + if (subControllers.length) { + for (var i = 0, length = subControllers.length; length > i; i++) { + controller = subControllers[i]; + + if (controller) { + controller.destroy(); + } + } + + subControllers.length = 0; + } + }, + + willDestroy: function() { + this._resetSubControllers(); + this._super(); + } + }); + }); +enifed("ember-runtime/controllers/controller", + ["ember-runtime/system/object","ember-runtime/mixins/controller","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var EmberObject = __dependency1__["default"]; + var Mixin = __dependency2__["default"]; + + /** + @module ember + @submodule ember-runtime + */ + + /** + @class Controller + @namespace Ember + @extends Ember.Object + @uses Ember.ControllerMixin + */ + __exports__["default"] = EmberObject.extend(Mixin); + }); +enifed("ember-runtime/controllers/object_controller", + ["ember-runtime/mixins/controller","ember-runtime/system/object_proxy","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var ControllerMixin = __dependency1__["default"]; + var ObjectProxy = __dependency2__["default"]; + + /** + @module ember + @submodule ember-runtime + */ + + /** + `Ember.ObjectController` is part of Ember's Controller layer. It is intended + to wrap a single object, proxying unhandled attempts to `get` and `set` to the underlying + model object, and to forward unhandled action attempts to its `target`. + + `Ember.ObjectController` derives this functionality from its superclass + `Ember.ObjectProxy` and the `Ember.ControllerMixin` mixin. + + @class ObjectController + @namespace Ember + @extends Ember.ObjectProxy + @uses Ember.ControllerMixin + **/ + __exports__["default"] = ObjectProxy.extend(ControllerMixin); + }); +enifed("ember-runtime/copy", + ["ember-metal/enumerable_utils","ember-metal/utils","ember-runtime/system/object","ember-runtime/mixins/copyable","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var indexOf = __dependency1__.indexOf; + var typeOf = __dependency2__.typeOf; + var EmberObject = __dependency3__["default"]; + var Copyable = __dependency4__["default"]; + + function _copy(obj, deep, seen, copies) { + var ret, loc, key; + + // primitive data types are immutable, just return them. + if (typeof obj !== 'object' || obj === null) { + return obj; + } + + // avoid cyclical loops + if (deep && (loc = indexOf(seen, obj)) >= 0) { + return copies[loc]; + } + + + // IMPORTANT: this specific test will detect a native array only. Any other + // object will need to implement Copyable. + if (typeOf(obj) === 'array') { + ret = obj.slice(); + + if (deep) { + loc = ret.length; + + while (--loc >= 0) { + ret[loc] = _copy(ret[loc], deep, seen, copies); + } + } + } else if (Copyable && Copyable.detect(obj)) { + ret = obj.copy(deep, seen, copies); + } else if (obj instanceof Date) { + ret = new Date(obj.getTime()); + } else { + ret = {}; + + for (key in obj) { + // support Null prototype + if (!Object.prototype.hasOwnProperty.call(obj, key)) { + continue; + } + + // Prevents browsers that don't respect non-enumerability from + // copying internal Ember properties + if (key.substring(0, 2) === '__') { + continue; + } + + ret[key] = deep ? _copy(obj[key], deep, seen, copies) : obj[key]; + } + } + + if (deep) { + seen.push(obj); + copies.push(ret); + } + + return ret; + } + + /** + Creates a clone of the passed object. This function can take just about + any type of object and create a clone of it, including primitive values + (which are not actually cloned because they are immutable). + + If the passed object implements the `clone()` method, then this function + will simply call that method and return the result. + + @method copy + @for Ember + @param {Object} obj The object to clone + @param {Boolean} deep If true, a deep copy of the object is made + @return {Object} The cloned object + */ + __exports__["default"] = function copy(obj, deep) { + // fast paths + if ('object' !== typeof obj || obj === null) { + return obj; // can't copy primitives + } + + if (Copyable && Copyable.detect(obj)) { + return obj.copy(deep); + } + + return _copy(obj, deep, deep ? [] : null, deep ? [] : null); + } + }); +enifed("ember-runtime/core", + ["exports"], + function(__exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + /** + Compares two objects, returning true if they are logically equal. This is + a deeper comparison than a simple triple equal. For sets it will compare the + internal objects. For any other object that implements `isEqual()` it will + respect that method. + + ```javascript + Ember.isEqual('hello', 'hello'); // true + Ember.isEqual(1, 2); // false + Ember.isEqual([4, 2], [4, 2]); // false + ``` + + @method isEqual + @for Ember + @param {Object} a first object to compare + @param {Object} b second object to compare + @return {Boolean} + */ + var isEqual = function isEqual(a, b) { + if (a && typeof a.isEqual === 'function') { + return a.isEqual(b); + } + + if (a instanceof Date && b instanceof Date) { + return a.getTime() === b.getTime(); + } + + return a === b; + }; + __exports__.isEqual = isEqual; + }); +enifed("ember-runtime/ext/function", + ["ember-metal/core","ember-metal/expand_properties","ember-metal/computed","ember-metal/mixin"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + // Ember.EXTEND_PROTOTYPES, Ember.assert + var expandProperties = __dependency2__["default"]; + var computed = __dependency3__.computed; + var observer = __dependency4__.observer; + + var a_slice = Array.prototype.slice; + var FunctionPrototype = Function.prototype; + + if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Function) { + + /** + The `property` extension of Javascript's Function prototype is available + when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is + `true`, which is the default. + + Computed properties allow you to treat a function like a property: + + ```javascript + MyApp.President = Ember.Object.extend({ + firstName: '', + lastName: '', + + fullName: function() { + return this.get('firstName') + ' ' + this.get('lastName'); + }.property() // Call this flag to mark the function as a property + }); + + var president = MyApp.President.create({ + firstName: 'Barack', + lastName: 'Obama' + }); + + president.get('fullName'); // 'Barack Obama' + ``` + + Treating a function like a property is useful because they can work with + bindings, just like any other property. + + Many computed properties have dependencies on other properties. For + example, in the above example, the `fullName` property depends on + `firstName` and `lastName` to determine its value. You can tell Ember + about these dependencies like this: + + ```javascript + MyApp.President = Ember.Object.extend({ + firstName: '', + lastName: '', + + fullName: function() { + return this.get('firstName') + ' ' + this.get('lastName'); + + // Tell Ember.js that this computed property depends on firstName + // and lastName + }.property('firstName', 'lastName') + }); + ``` + + Make sure you list these dependencies so Ember knows when to update + bindings that connect to a computed property. Changing a dependency + will not immediately trigger an update of the computed property, but + will instead clear the cache so that it is updated when the next `get` + is called on the property. + + See [Ember.ComputedProperty](/api/classes/Ember.ComputedProperty.html), [Ember.computed](/api/#method_computed). + + @method property + @for Function + */ + FunctionPrototype.property = function () { + var ret = computed(this); + // ComputedProperty.prototype.property expands properties; no need for us to + // do so here. + return ret.property.apply(ret, arguments); + }; + + /** + The `observes` extension of Javascript's Function prototype is available + when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is + true, which is the default. + + You can observe property changes simply by adding the `observes` + call to the end of your method declarations in classes that you write. + For example: + + ```javascript + Ember.Object.extend({ + valueObserver: function() { + // Executes whenever the "value" property changes + }.observes('value') + }); + ``` + + In the future this method may become asynchronous. If you want to ensure + synchronous behavior, use `observesImmediately`. + + See `Ember.observer`. + + @method observes + @for Function + */ + FunctionPrototype.observes = function() { + var length = arguments.length; + var args = new Array(length); + for (var x = 0; x < length; x++) { + args[x] = arguments[x]; + } + return observer.apply(this, args.concat(this)); + }; + + /** + The `observesImmediately` extension of Javascript's Function prototype is + available when `Ember.EXTEND_PROTOTYPES` or + `Ember.EXTEND_PROTOTYPES.Function` is true, which is the default. + + You can observe property changes simply by adding the `observesImmediately` + call to the end of your method declarations in classes that you write. + For example: + + ```javascript + Ember.Object.extend({ + valueObserver: function() { + // Executes immediately after the "value" property changes + }.observesImmediately('value') + }); + ``` + + In the future, `observes` may become asynchronous. In this event, + `observesImmediately` will maintain the synchronous behavior. + + See `Ember.immediateObserver`. + + @method observesImmediately + @for Function + */ + FunctionPrototype.observesImmediately = function () { + for (var i = 0, l = arguments.length; i < l; i++) { + var arg = arguments[i]; + } + + // observes handles property expansion + return this.observes.apply(this, arguments); + }; + + /** + The `observesBefore` extension of Javascript's Function prototype is + available when `Ember.EXTEND_PROTOTYPES` or + `Ember.EXTEND_PROTOTYPES.Function` is true, which is the default. + + You can get notified when a property change is about to happen by + by adding the `observesBefore` call to the end of your method + declarations in classes that you write. For example: + + ```javascript + Ember.Object.extend({ + valueObserver: function() { + // Executes whenever the "value" property is about to change + }.observesBefore('value') + }); + ``` + + See `Ember.beforeObserver`. + + @method observesBefore + @for Function + */ + FunctionPrototype.observesBefore = function () { + var watched = []; + var addWatchedProperty = function (obs) { + watched.push(obs); + }; + + for (var i = 0, l = arguments.length; i < l; ++i) { + expandProperties(arguments[i], addWatchedProperty); + } + + this.__ember_observesBefore__ = watched; + + return this; + }; + + /** + The `on` extension of Javascript's Function prototype is available + when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is + true, which is the default. + + You can listen for events simply by adding the `on` call to the end of + your method declarations in classes or mixins that you write. For example: + + ```javascript + Ember.Mixin.create({ + doSomethingWithElement: function() { + // Executes whenever the "didInsertElement" event fires + }.on('didInsertElement') + }); + ``` + + See `Ember.on`. + + @method on + @for Function + */ + FunctionPrototype.on = function () { + var events = a_slice.call(arguments); + this.__ember_listens__ = events; + + return this; + }; + } + }); +enifed("ember-runtime/ext/rsvp", + ["ember-metal/core","ember-metal/logger","ember-metal/run_loop","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + /* globals RSVP:true */ + + var Ember = __dependency1__["default"]; + var Logger = __dependency2__["default"]; + var run = __dependency3__["default"]; + + var RSVP = requireModule('rsvp'); + var testModuleName = 'ember-testing/test'; + var Test; + + var asyncStart = function() { + if (Ember.Test && Ember.Test.adapter) { + Ember.Test.adapter.asyncStart(); + } + }; + + var asyncEnd = function() { + if (Ember.Test && Ember.Test.adapter) { + Ember.Test.adapter.asyncEnd(); + } + }; + + RSVP.configure('async', function(callback, promise) { + var async = !run.currentRunLoop; + + if (Ember.testing && async) { asyncStart(); } + + run.backburner.schedule('actions', function(){ + if (Ember.testing && async) { asyncEnd(); } + callback(promise); + }); + }); + + RSVP.Promise.prototype.fail = function(callback, label){ + return this['catch'](callback, label); + }; + + RSVP.onerrorDefault = function (error) { + if (error instanceof Error) { + if (Ember.testing) { + // ES6TODO: remove when possible + if (!Test && Ember.__loader.registry[testModuleName]) { + Test = requireModule(testModuleName)['default']; + } + + if (Test && Test.adapter) { + Test.adapter.exception(error); + } else { + throw error; + } + } else if (Ember.onerror) { + Ember.onerror(error); + } else { + Logger.error(error.stack); + } + } + }; + + RSVP.on('error', RSVP.onerrorDefault); + + __exports__["default"] = RSVP; + }); +enifed("ember-runtime/ext/string", + ["ember-metal/core","ember-runtime/system/string"], + function(__dependency1__, __dependency2__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + // Ember.EXTEND_PROTOTYPES, Ember.assert, Ember.FEATURES + var fmt = __dependency2__.fmt; + var w = __dependency2__.w; + var loc = __dependency2__.loc; + var camelize = __dependency2__.camelize; + var decamelize = __dependency2__.decamelize; + var dasherize = __dependency2__.dasherize; + var underscore = __dependency2__.underscore; + var capitalize = __dependency2__.capitalize; + var classify = __dependency2__.classify; + + var StringPrototype = String.prototype; + + if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) { + + /** + See [Ember.String.fmt](/api/classes/Ember.String.html#method_fmt). + + @method fmt + @for String + */ + StringPrototype.fmt = function () { + return fmt(this, arguments); + }; + + /** + See [Ember.String.w](/api/classes/Ember.String.html#method_w). + + @method w + @for String + */ + StringPrototype.w = function () { + return w(this); + }; + + /** + See [Ember.String.loc](/api/classes/Ember.String.html#method_loc). + + @method loc + @for String + */ + StringPrototype.loc = function () { + return loc(this, arguments); + }; + + /** + See [Ember.String.camelize](/api/classes/Ember.String.html#method_camelize). + + @method camelize + @for String + */ + StringPrototype.camelize = function () { + return camelize(this); + }; + + /** + See [Ember.String.decamelize](/api/classes/Ember.String.html#method_decamelize). + + @method decamelize + @for String + */ + StringPrototype.decamelize = function () { + return decamelize(this); + }; + + /** + See [Ember.String.dasherize](/api/classes/Ember.String.html#method_dasherize). + + @method dasherize + @for String + */ + StringPrototype.dasherize = function () { + return dasherize(this); + }; + + /** + See [Ember.String.underscore](/api/classes/Ember.String.html#method_underscore). + + @method underscore + @for String + */ + StringPrototype.underscore = function () { + return underscore(this); + }; + + /** + See [Ember.String.classify](/api/classes/Ember.String.html#method_classify). + + @method classify + @for String + */ + StringPrototype.classify = function () { + return classify(this); + }; + + /** + See [Ember.String.capitalize](/api/classes/Ember.String.html#method_capitalize). + + @method capitalize + @for String + */ + StringPrototype.capitalize = function () { + return capitalize(this); + }; + } + }); +enifed("ember-runtime/mixins/-proxy", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/observer","ember-metal/property_events","ember-metal/computed","ember-metal/properties","ember-metal/mixin","ember-runtime/system/string","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + // Ember.assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var meta = __dependency4__.meta; + var addObserver = __dependency5__.addObserver; + var removeObserver = __dependency5__.removeObserver; + var addBeforeObserver = __dependency5__.addBeforeObserver; + var removeBeforeObserver = __dependency5__.removeBeforeObserver; + var propertyWillChange = __dependency6__.propertyWillChange; + var propertyDidChange = __dependency6__.propertyDidChange; + var computed = __dependency7__.computed; + var defineProperty = __dependency8__.defineProperty; + var Mixin = __dependency9__.Mixin; + var observer = __dependency9__.observer; + var fmt = __dependency10__.fmt; + var EmberObject = __dependency11__["default"]; + + function contentPropertyWillChange(content, contentKey) { + var key = contentKey.slice(8); // remove "content." + if (key in this) { return; } // if shadowed in proxy + propertyWillChange(this, key); + } + + function contentPropertyDidChange(content, contentKey) { + var key = contentKey.slice(8); // remove "content." + if (key in this) { return; } // if shadowed in proxy + propertyDidChange(this, key); + } + + /** + `Ember.ProxyMixin` forwards all properties not defined by the proxy itself + to a proxied `content` object. See Ember.ObjectProxy for more details. + + @class ProxyMixin + @namespace Ember + */ + __exports__["default"] = Mixin.create({ + /** + The object whose properties will be forwarded. + + @property content + @type Ember.Object + @default null + */ + content: null, + _contentDidChange: observer('content', function() { + }), + + isTruthy: computed.bool('content'), + + _debugContainerKey: null, + + willWatchProperty: function (key) { + var contentKey = 'content.' + key; + addBeforeObserver(this, contentKey, null, contentPropertyWillChange); + addObserver(this, contentKey, null, contentPropertyDidChange); + }, + + didUnwatchProperty: function (key) { + var contentKey = 'content.' + key; + removeBeforeObserver(this, contentKey, null, contentPropertyWillChange); + removeObserver(this, contentKey, null, contentPropertyDidChange); + }, + + unknownProperty: function (key) { + var content = get(this, 'content'); + if (content) { + return get(content, key); + } + }, + + setUnknownProperty: function (key, value) { + var m = meta(this); + if (m.proto === this) { + // if marked as prototype then just defineProperty + // rather than delegate + defineProperty(this, key, null, value); + return value; + } + + var content = get(this, 'content'); + return set(content, key, value); + } + + }); + }); +enifed("ember-runtime/mixins/action_handler", + ["ember-metal/merge","ember-metal/mixin","ember-metal/property_get","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + var merge = __dependency1__["default"]; + var Mixin = __dependency2__.Mixin; + var get = __dependency3__.get; + var typeOf = __dependency4__.typeOf; + + /** + The `Ember.ActionHandler` mixin implements support for moving an `actions` + property to an `_actions` property at extend time, and adding `_actions` + to the object's mergedProperties list. + + `Ember.ActionHandler` is available on some familiar classes including + `Ember.Route`, `Ember.View`, `Ember.Component`, and controllers such as + `Ember.Controller` and `Ember.ObjectController`. + (Internally the mixin is used by `Ember.CoreView`, `Ember.ControllerMixin`, + and `Ember.Route` and available to the above classes through + inheritance.) + + @class ActionHandler + @namespace Ember + */ + var ActionHandler = Mixin.create({ + mergedProperties: ['_actions'], + + /** + The collection of functions, keyed by name, available on this + `ActionHandler` as action targets. + + These functions will be invoked when a matching `{{action}}` is triggered + from within a template and the application's current route is this route. + + Actions can also be invoked from other parts of your application + via `ActionHandler#send`. + + The `actions` hash will inherit action handlers from + the `actions` hash defined on extended parent classes + or mixins rather than just replace the entire hash, e.g.: + + ```js + App.CanDisplayBanner = Ember.Mixin.create({ + actions: { + displayBanner: function(msg) { + // ... + } + } + }); + + App.WelcomeRoute = Ember.Route.extend(App.CanDisplayBanner, { + actions: { + playMusic: function() { + // ... + } + } + }); + + // `WelcomeRoute`, when active, will be able to respond + // to both actions, since the actions hash is merged rather + // then replaced when extending mixins / parent classes. + this.send('displayBanner'); + this.send('playMusic'); + ``` + + Within a Controller, Route, View or Component's action handler, + the value of the `this` context is the Controller, Route, View or + Component object: + + ```js + App.SongRoute = Ember.Route.extend({ + actions: { + myAction: function() { + this.controllerFor("song"); + this.transitionTo("other.route"); + ... + } + } + }); + ``` + + It is also possible to call `this._super()` from within an + action handler if it overrides a handler defined on a parent + class or mixin: + + Take for example the following routes: + + ```js + App.DebugRoute = Ember.Mixin.create({ + actions: { + debugRouteInformation: function() { + console.debug("trololo"); + } + } + }); + + App.AnnoyingDebugRoute = Ember.Route.extend(App.DebugRoute, { + actions: { + debugRouteInformation: function() { + // also call the debugRouteInformation of mixed in App.DebugRoute + this._super(); + + // show additional annoyance + window.alert(...); + } + } + }); + ``` + + ## Bubbling + + By default, an action will stop bubbling once a handler defined + on the `actions` hash handles it. To continue bubbling the action, + you must return `true` from the handler: + + ```js + App.Router.map(function() { + this.resource("album", function() { + this.route("song"); + }); + }); + + App.AlbumRoute = Ember.Route.extend({ + actions: { + startPlaying: function() { + } + } + }); + + App.AlbumSongRoute = Ember.Route.extend({ + actions: { + startPlaying: function() { + // ... + + if (actionShouldAlsoBeTriggeredOnParentRoute) { + return true; + } + } + } + }); + ``` + + @property actions + @type Hash + @default null + */ + + /** + Moves `actions` to `_actions` at extend time. Note that this currently + modifies the mixin themselves, which is technically dubious but + is practically of little consequence. This may change in the future. + + @private + @method willMergeMixin + */ + willMergeMixin: function(props) { + var hashName; + + if (!props._actions) { + + if (typeOf(props.actions) === 'object') { + hashName = 'actions'; + } else if (typeOf(props.events) === 'object') { + hashName = 'events'; + } + + if (hashName) { + props._actions = merge(props._actions || {}, props[hashName]); + } + + delete props[hashName]; + } + }, + + /** + Triggers a named action on the `ActionHandler`. Any parameters + supplied after the `actionName` string will be passed as arguments + to the action target function. + + If the `ActionHandler` has its `target` property set, actions may + bubble to the `target`. Bubbling happens when an `actionName` can + not be found in the `ActionHandler`'s `actions` hash or if the + action target function returns `true`. + + Example + + ```js + App.WelcomeRoute = Ember.Route.extend({ + actions: { + playTheme: function() { + this.send('playMusic', 'theme.mp3'); + }, + playMusic: function(track) { + // ... + } + } + }); + ``` + + @method send + @param {String} actionName The action to trigger + @param {*} context a context to send with the action + */ + send: function(actionName) { + var args = [].slice.call(arguments, 1); + var target; + + if (this._actions && this._actions[actionName]) { + if (this._actions[actionName].apply(this, args) === true) { + // handler returned true, so this action will bubble + } else { + return; + } + } + + if (target = get(this, 'target')) { + target.send.apply(target, arguments); + } + } + }); + + __exports__["default"] = ActionHandler; + }); +enifed("ember-runtime/mixins/array", + ["ember-metal/core","ember-metal/property_get","ember-metal/computed","ember-metal/is_none","ember-runtime/mixins/enumerable","ember-metal/enumerable_utils","ember-metal/mixin","ember-metal/property_events","ember-metal/events","ember-metal/watching","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + // .......................................................... + // HELPERS + // + var Ember = __dependency1__["default"]; + // ES6TODO: Ember.A + var get = __dependency2__.get; + var computed = __dependency3__.computed; + var cacheFor = __dependency3__.cacheFor; + var isNone = __dependency4__.isNone; + var none = __dependency4__.none; + var Enumerable = __dependency5__["default"]; + var map = __dependency6__.map; + var Mixin = __dependency7__.Mixin; + var required = __dependency7__.required; + var propertyWillChange = __dependency8__.propertyWillChange; + var propertyDidChange = __dependency8__.propertyDidChange; + var addListener = __dependency9__.addListener; + var removeListener = __dependency9__.removeListener; + var sendEvent = __dependency9__.sendEvent; + var hasListeners = __dependency9__.hasListeners; + var isWatching = __dependency10__.isWatching; + + function arrayObserversHelper(obj, target, opts, operation, notify) { + var willChange = (opts && opts.willChange) || 'arrayWillChange'; + var didChange = (opts && opts.didChange) || 'arrayDidChange'; + var hasObservers = get(obj, 'hasArrayObservers'); + + if (hasObservers === notify) { + propertyWillChange(obj, 'hasArrayObservers'); + } + + operation(obj, '@array:before', target, willChange); + operation(obj, '@array:change', target, didChange); + + if (hasObservers === notify) { + propertyDidChange(obj, 'hasArrayObservers'); + } + + return obj; + } + + // .......................................................... + // ARRAY + // + /** + This mixin implements Observer-friendly Array-like behavior. It is not a + concrete implementation, but it can be used up by other classes that want + to appear like arrays. + + For example, ArrayProxy and ArrayController are both concrete classes that can + be instantiated to implement array-like behavior. Both of these classes use + the Array Mixin by way of the MutableArray mixin, which allows observable + changes to be made to the underlying array. + + Unlike `Ember.Enumerable,` this mixin defines methods specifically for + collections that provide index-ordered access to their contents. When you + are designing code that needs to accept any kind of Array-like object, you + should use these methods instead of Array primitives because these will + properly notify observers of changes to the array. + + Although these methods are efficient, they do add a layer of indirection to + your application so it is a good idea to use them only when you need the + flexibility of using both true JavaScript arrays and "virtual" arrays such + as controllers and collections. + + You can use the methods defined in this module to access and modify array + contents in a KVO-friendly way. You can also be notified whenever the + membership of an array changes by using `.observes('myArray.[]')`. + + To support `Ember.Array` in your own class, you must override two + primitives to use it: `replace()` and `objectAt()`. + + Note that the Ember.Array mixin also incorporates the `Ember.Enumerable` + mixin. All `Ember.Array`-like objects are also enumerable. + + @class Array + @namespace Ember + @uses Ember.Enumerable + @since Ember 0.9.0 + */ + __exports__["default"] = Mixin.create(Enumerable, { + + /** + Your array must support the `length` property. Your replace methods should + set this property whenever it changes. + + @property {Number} length + */ + length: required(), + + /** + Returns the object at the given `index`. If the given `index` is negative + or is greater or equal than the array length, returns `undefined`. + + This is one of the primitives you must implement to support `Ember.Array`. + If your object supports retrieving the value of an array item using `get()` + (i.e. `myArray.get(0)`), then you do not need to implement this method + yourself. + + ```javascript + var arr = ['a', 'b', 'c', 'd']; + + arr.objectAt(0); // 'a' + arr.objectAt(3); // 'd' + arr.objectAt(-1); // undefined + arr.objectAt(4); // undefined + arr.objectAt(5); // undefined + ``` + + @method objectAt + @param {Number} idx The index of the item to return. + @return {*} item at index or undefined + */ + objectAt: function(idx) { + if (idx < 0 || idx >= get(this, 'length')) { + return undefined; + } + + return get(this, idx); + }, + + /** + This returns the objects at the specified indexes, using `objectAt`. + + ```javascript + var arr = ['a', 'b', 'c', 'd']; + + arr.objectsAt([0, 1, 2]); // ['a', 'b', 'c'] + arr.objectsAt([2, 3, 4]); // ['c', 'd', undefined] + ``` + + @method objectsAt + @param {Array} indexes An array of indexes of items to return. + @return {Array} + */ + objectsAt: function(indexes) { + var self = this; + + return map(indexes, function(idx) { + return self.objectAt(idx); + }); + }, + + // overrides Ember.Enumerable version + nextObject: function(idx) { + return this.objectAt(idx); + }, + + /** + This is the handler for the special array content property. If you get + this property, it will return this. If you set this property to a new + array, it will replace the current content. + + This property overrides the default property defined in `Ember.Enumerable`. + + @property [] + @return this + */ + '[]': computed(function(key, value) { + if (value !== undefined) { + this.replace(0, get(this, 'length'), value); + } + + return this; + }), + + firstObject: computed(function() { + return this.objectAt(0); + }), + + lastObject: computed(function() { + return this.objectAt(get(this, 'length') - 1); + }), + + // optimized version from Enumerable + contains: function(obj) { + return this.indexOf(obj) >= 0; + }, + + // Add any extra methods to Ember.Array that are native to the built-in Array. + /** + Returns a new array that is a slice of the receiver. This implementation + uses the observable array methods to retrieve the objects for the new + slice. + + ```javascript + var arr = ['red', 'green', 'blue']; + + arr.slice(0); // ['red', 'green', 'blue'] + arr.slice(0, 2); // ['red', 'green'] + arr.slice(1, 100); // ['green', 'blue'] + ``` + + @method slice + @param {Integer} beginIndex (Optional) index to begin slicing from. + @param {Integer} endIndex (Optional) index to end the slice at (but not included). + @return {Array} New array with specified slice + */ + slice: function(beginIndex, endIndex) { + var ret = Ember.A(); + var length = get(this, 'length'); + + if (isNone(beginIndex)) { + beginIndex = 0; + } + + if (isNone(endIndex) || (endIndex > length)) { + endIndex = length; + } + + if (beginIndex < 0) { + beginIndex = length + beginIndex; + } + + if (endIndex < 0) { + endIndex = length + endIndex; + } + + while (beginIndex < endIndex) { + ret[ret.length] = this.objectAt(beginIndex++); + } + + return ret; + }, + + /** + Returns the index of the given object's first occurrence. + If no `startAt` argument is given, the starting location to + search is 0. If it's negative, will count backward from + the end of the array. Returns -1 if no match is found. + + ```javascript + var arr = ['a', 'b', 'c', 'd', 'a']; + + arr.indexOf('a'); // 0 + arr.indexOf('z'); // -1 + arr.indexOf('a', 2); // 4 + arr.indexOf('a', -1); // 4 + arr.indexOf('b', 3); // -1 + arr.indexOf('a', 100); // -1 + ``` + + @method indexOf + @param {Object} object the item to search for + @param {Number} startAt optional starting location to search, default 0 + @return {Number} index or -1 if not found + */ + indexOf: function(object, startAt) { + var len = get(this, 'length'); + var idx; + + if (startAt === undefined) { + startAt = 0; + } + + if (startAt < 0) { + startAt += len; + } + + for (idx = startAt; idx < len; idx++) { + if (this.objectAt(idx) === object) { + return idx; + } + } + + return -1; + }, + + /** + Returns the index of the given object's last occurrence. + If no `startAt` argument is given, the search starts from + the last position. If it's negative, will count backward + from the end of the array. Returns -1 if no match is found. + + ```javascript + var arr = ['a', 'b', 'c', 'd', 'a']; + + arr.lastIndexOf('a'); // 4 + arr.lastIndexOf('z'); // -1 + arr.lastIndexOf('a', 2); // 0 + arr.lastIndexOf('a', -1); // 4 + arr.lastIndexOf('b', 3); // 1 + arr.lastIndexOf('a', 100); // 4 + ``` + + @method lastIndexOf + @param {Object} object the item to search for + @param {Number} startAt optional starting location to search, default 0 + @return {Number} index or -1 if not found + */ + lastIndexOf: function(object, startAt) { + var len = get(this, 'length'); + var idx; + + if (startAt === undefined || startAt >= len) { + startAt = len-1; + } + + if (startAt < 0) { + startAt += len; + } + + for (idx = startAt; idx >= 0; idx--) { + if (this.objectAt(idx) === object) { + return idx; + } + } + + return -1; + }, + + // .......................................................... + // ARRAY OBSERVERS + // + + /** + Adds an array observer to the receiving array. The array observer object + normally must implement two methods: + + * `arrayWillChange(observedObj, start, removeCount, addCount)` - This method will be + called just before the array is modified. + * `arrayDidChange(observedObj, start, removeCount, addCount)` - This method will be + called just after the array is modified. + + Both callbacks will be passed the observed object, starting index of the + change as well a a count of the items to be removed and added. You can use + these callbacks to optionally inspect the array during the change, clear + caches, or do any other bookkeeping necessary. + + In addition to passing a target, you can also include an options hash + which you can use to override the method names that will be invoked on the + target. + + @method addArrayObserver + @param {Object} target The observer object. + @param {Hash} opts Optional hash of configuration options including + `willChange` and `didChange` option. + @return {Ember.Array} receiver + */ + + addArrayObserver: function(target, opts) { + return arrayObserversHelper(this, target, opts, addListener, false); + }, + + /** + Removes an array observer from the object if the observer is current + registered. Calling this method multiple times with the same object will + have no effect. + + @method removeArrayObserver + @param {Object} target The object observing the array. + @param {Hash} opts Optional hash of configuration options including + `willChange` and `didChange` option. + @return {Ember.Array} receiver + */ + removeArrayObserver: function(target, opts) { + return arrayObserversHelper(this, target, opts, removeListener, true); + }, + + /** + Becomes true whenever the array currently has observers watching changes + on the array. + + @property {Boolean} hasArrayObservers + */ + hasArrayObservers: computed(function() { + return hasListeners(this, '@array:change') || hasListeners(this, '@array:before'); + }), + + /** + If you are implementing an object that supports `Ember.Array`, call this + method just before the array content changes to notify any observers and + invalidate any related properties. Pass the starting index of the change + as well as a delta of the amounts to change. + + @method arrayContentWillChange + @param {Number} startIdx The starting index in the array that will change. + @param {Number} removeAmt The number of items that will be removed. If you + pass `null` assumes 0 + @param {Number} addAmt The number of items that will be added. If you + pass `null` assumes 0. + @return {Ember.Array} receiver + */ + arrayContentWillChange: function(startIdx, removeAmt, addAmt) { + var removing, lim; + + // if no args are passed assume everything changes + if (startIdx === undefined) { + startIdx = 0; + removeAmt = addAmt = -1; + } else { + if (removeAmt === undefined) { + removeAmt = -1; + } + + if (addAmt === undefined) { + addAmt = -1; + } + } + + // Make sure the @each proxy is set up if anyone is observing @each + if (isWatching(this, '@each')) { + get(this, '@each'); + } + + sendEvent(this, '@array:before', [this, startIdx, removeAmt, addAmt]); + + if (startIdx >= 0 && removeAmt >= 0 && get(this, 'hasEnumerableObservers')) { + removing = []; + lim = startIdx + removeAmt; + + for (var idx = startIdx; idx < lim; idx++) { + removing.push(this.objectAt(idx)); + } + } else { + removing = removeAmt; + } + + this.enumerableContentWillChange(removing, addAmt); + + return this; + }, + + /** + If you are implementing an object that supports `Ember.Array`, call this + method just after the array content changes to notify any observers and + invalidate any related properties. Pass the starting index of the change + as well as a delta of the amounts to change. + + @method arrayContentDidChange + @param {Number} startIdx The starting index in the array that did change. + @param {Number} removeAmt The number of items that were removed. If you + pass `null` assumes 0 + @param {Number} addAmt The number of items that were added. If you + pass `null` assumes 0. + @return {Ember.Array} receiver + */ + arrayContentDidChange: function(startIdx, removeAmt, addAmt) { + var adding, lim; + + // if no args are passed assume everything changes + if (startIdx === undefined) { + startIdx = 0; + removeAmt = addAmt = -1; + } else { + if (removeAmt === undefined) { + removeAmt = -1; + } + + if (addAmt === undefined) { + addAmt = -1; + } + } + + if (startIdx >= 0 && addAmt >= 0 && get(this, 'hasEnumerableObservers')) { + adding = []; + lim = startIdx + addAmt; + + for (var idx = startIdx; idx < lim; idx++) { + adding.push(this.objectAt(idx)); + } + } else { + adding = addAmt; + } + + this.enumerableContentDidChange(removeAmt, adding); + sendEvent(this, '@array:change', [this, startIdx, removeAmt, addAmt]); + + var length = get(this, 'length'); + var cachedFirst = cacheFor(this, 'firstObject'); + var cachedLast = cacheFor(this, 'lastObject'); + + if (this.objectAt(0) !== cachedFirst) { + propertyWillChange(this, 'firstObject'); + propertyDidChange(this, 'firstObject'); + } + + if (this.objectAt(length-1) !== cachedLast) { + propertyWillChange(this, 'lastObject'); + propertyDidChange(this, 'lastObject'); + } + + return this; + }, + + // .......................................................... + // ENUMERATED PROPERTIES + // + + /** + Returns a special object that can be used to observe individual properties + on the array. Just get an equivalent property on this object and it will + return an enumerable that maps automatically to the named key on the + member objects. + + If you merely want to watch for any items being added or removed to the array, + use the `[]` property instead of `@each`. + + @property @each + */ + '@each': computed(function() { + if (!this.__each) { + // ES6TODO: GRRRRR + var EachProxy = requireModule('ember-runtime/system/each_proxy')['EachProxy']; + + this.__each = new EachProxy(this); + } + + return this.__each; + }) + }); + }); +enifed("ember-runtime/mixins/comparable", + ["ember-metal/mixin","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Mixin = __dependency1__.Mixin; + var required = __dependency1__.required; + + /** + @module ember + @submodule ember-runtime + */ + + /** + Implements some standard methods for comparing objects. Add this mixin to + any class you create that can compare its instances. + + You should implement the `compare()` method. + + @class Comparable + @namespace Ember + @since Ember 0.9 + */ + __exports__["default"] = Mixin.create({ + + /** + Override to return the result of the comparison of the two parameters. The + compare method should return: + + - `-1` if `a < b` + - `0` if `a == b` + - `1` if `a > b` + + Default implementation raises an exception. + + @method compare + @param a {Object} the first object to compare + @param b {Object} the second object to compare + @return {Integer} the result of the comparison + */ + compare: required(Function) + }); + }); +enifed("ember-runtime/mixins/controller", + ["ember-metal/core","ember-metal/property_get","ember-runtime/system/object","ember-metal/mixin","ember-metal/computed","ember-runtime/mixins/action_handler","ember-runtime/mixins/controller_content_model_alias_deprecation","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert, Ember.deprecate + var get = __dependency2__.get; + var EmberObject = __dependency3__["default"]; + var Mixin = __dependency4__.Mixin; + var computed = __dependency5__.computed; + var ActionHandler = __dependency6__["default"]; + var ControllerContentModelAliasDeprecation = __dependency7__["default"]; + + /** + `Ember.ControllerMixin` provides a standard interface for all classes that + compose Ember's controller layer: `Ember.Controller`, + `Ember.ArrayController`, and `Ember.ObjectController`. + + @class ControllerMixin + @namespace Ember + @uses Ember.ActionHandler + */ + __exports__["default"] = Mixin.create(ActionHandler, ControllerContentModelAliasDeprecation, { + /* ducktype as a controller */ + isController: true, + + /** + The object to which actions from the view should be sent. + + For example, when a Handlebars template uses the `{{action}}` helper, + it will attempt to send the action to the view's controller's `target`. + + By default, the value of the target property is set to the router, and + is injected when a controller is instantiated. This injection is defined + in Ember.Application#buildContainer, and is applied as part of the + applications initialization process. It can also be set after a controller + has been instantiated, for instance when using the render helper in a + template, or when a controller is used as an `itemController`. In most + cases the `target` property will automatically be set to the logical + consumer of actions for the controller. + + @property target + @default null + */ + target: null, + + container: null, + + parentController: null, + + store: null, + + /** + The controller's current model. When retrieving or modifying a controller's + model, this property should be used instead of the `content` property. + + @property model + @public + */ + model: null, + + /** + @private + */ + content: computed.alias('model') + + }); + }); +enifed("ember-runtime/mixins/controller_content_model_alias_deprecation", + ["ember-metal/core","ember-metal/property_get","ember-metal/mixin","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.deprecate + var get = __dependency2__.get; + var Mixin = __dependency3__.Mixin; + + /** + The ControllerContentModelAliasDeprecation mixin is used to provide a useful + deprecation warning when specifying `content` directly on a `Ember.Controller` + (without also specifying `model`). + + Ember versions prior to 1.7 used `model` as an alias of `content`, but due to + much confusion this alias was reversed (so `content` is now an alias of `model). + + This change reduces many caveats with model/content, and also sets a + simple ground rule: Never set a controllers content, rather always set + it's model and ember will do the right thing. + + + `Ember.ControllerContentModelAliasDeprecation` is used internally by Ember in + `Ember.Controller`. + + @class ControllerContentModelAliasDeprecation + @namespace Ember + @private + @since 1.7.0 + */ + __exports__["default"] = Mixin.create({ + /** + @private + + Moves `content` to `model` at extend time if a `model` is not also specified. + + Note that this currently modifies the mixin themselves, which is technically + dubious but is practically of little consequence. This may change in the + future. + + @method willMergeMixin + @since 1.4.0 + */ + willMergeMixin: function(props) { + // Calling super is only OK here since we KNOW that + // there is another Mixin loaded first. + this._super.apply(this, arguments); + + var modelSpecified = !!props.model; + + if (props.content && !modelSpecified) { + props.model = props.content; + delete props['content']; + + } + } + }); + }); +enifed("ember-runtime/mixins/copyable", + ["ember-metal/property_get","ember-metal/property_set","ember-metal/mixin","ember-runtime/mixins/freezable","ember-runtime/system/string","ember-metal/error","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + + var get = __dependency1__.get; + var set = __dependency2__.set; + var required = __dependency3__.required; + var Freezable = __dependency4__.Freezable; + var Mixin = __dependency3__.Mixin; + var fmt = __dependency5__.fmt; + var EmberError = __dependency6__["default"]; + + + /** + Implements some standard methods for copying an object. Add this mixin to + any object you create that can create a copy of itself. This mixin is + added automatically to the built-in array. + + You should generally implement the `copy()` method to return a copy of the + receiver. + + Note that `frozenCopy()` will only work if you also implement + `Ember.Freezable`. + + @class Copyable + @namespace Ember + @since Ember 0.9 + */ + __exports__["default"] = Mixin.create({ + /** + Override to return a copy of the receiver. Default implementation raises + an exception. + + @method copy + @param {Boolean} deep if `true`, a deep copy of the object should be made + @return {Object} copy of receiver + */ + copy: required(Function), + + /** + If the object implements `Ember.Freezable`, then this will return a new + copy if the object is not frozen and the receiver if the object is frozen. + + Raises an exception if you try to call this method on a object that does + not support freezing. + + You should use this method whenever you want a copy of a freezable object + since a freezable object can simply return itself without actually + consuming more memory. + + @method frozenCopy + @return {Object} copy of receiver or receiver + */ + frozenCopy: function() { + if (Freezable && Freezable.detect(this)) { + return get(this, 'isFrozen') ? this : this.copy().freeze(); + } else { + throw new EmberError(fmt("%@ does not support freezing", [this])); + } + } + }); + }); +enifed("ember-runtime/mixins/deferred", + ["ember-metal/core","ember-metal/property_get","ember-metal/mixin","ember-metal/computed","ember-runtime/ext/rsvp","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.FEATURES, Ember.Test + var get = __dependency2__.get; + var Mixin = __dependency3__.Mixin; + var computed = __dependency4__.computed; + var RSVP = __dependency5__["default"]; + + /** + @module ember + @submodule ember-runtime + */ + + + /** + @class Deferred + @namespace Ember + */ + __exports__["default"] = Mixin.create({ + /** + Add handlers to be called when the Deferred object is resolved or rejected. + + @method then + @param {Function} resolve a callback function to be called when done + @param {Function} reject a callback function to be called when failed + */ + then: function(resolve, reject, label) { + var deferred, promise, entity; + + entity = this; + deferred = get(this, '_deferred'); + promise = deferred.promise; + + function fulfillmentHandler(fulfillment) { + if (fulfillment === promise) { + return resolve(entity); + } else { + return resolve(fulfillment); + } + } + + return promise.then(resolve && fulfillmentHandler, reject, label); + }, + + /** + Resolve a Deferred object and call any `doneCallbacks` with the given args. + + @method resolve + */ + resolve: function(value) { + var deferred, promise; + + deferred = get(this, '_deferred'); + promise = deferred.promise; + + if (value === this) { + deferred.resolve(promise); + } else { + deferred.resolve(value); + } + }, + + /** + Reject a Deferred object and call any `failCallbacks` with the given args. + + @method reject + */ + reject: function(value) { + get(this, '_deferred').reject(value); + }, + + _deferred: computed(function() { + + return RSVP.defer('Ember: DeferredMixin - ' + this); + }) + }); + }); +enifed("ember-runtime/mixins/enumerable", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/mixin","ember-metal/enumerable_utils","ember-metal/computed","ember-metal/property_events","ember-metal/events","ember-runtime/compare","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + // .......................................................... + // HELPERS + // + + var Ember = __dependency1__["default"]; + var get = __dependency2__.get; + var set = __dependency3__.set; + var apply = __dependency4__.apply; + var Mixin = __dependency5__.Mixin; + var required = __dependency5__.required; + var aliasMethod = __dependency5__.aliasMethod; + var indexOf = __dependency6__.indexOf; + var computed = __dependency7__.computed; + var propertyWillChange = __dependency8__.propertyWillChange; + var propertyDidChange = __dependency8__.propertyDidChange; + var addListener = __dependency9__.addListener; + var removeListener = __dependency9__.removeListener; + var sendEvent = __dependency9__.sendEvent; + var hasListeners = __dependency9__.hasListeners; + var compare = __dependency10__["default"]; + + var a_slice = Array.prototype.slice; + + var contexts = []; + + function popCtx() { + return contexts.length===0 ? {} : contexts.pop(); + } + + function pushCtx(ctx) { + contexts.push(ctx); + return null; + } + + function iter(key, value) { + var valueProvided = arguments.length === 2; + + function i(item) { + var cur = get(item, key); + return valueProvided ? value===cur : !!cur; + } + + return i; + } + + /** + This mixin defines the common interface implemented by enumerable objects + in Ember. Most of these methods follow the standard Array iteration + API defined up to JavaScript 1.8 (excluding language-specific features that + cannot be emulated in older versions of JavaScript). + + This mixin is applied automatically to the Array class on page load, so you + can use any of these methods on simple arrays. If Array already implements + one of these methods, the mixin will not override them. + + ## Writing Your Own Enumerable + + To make your own custom class enumerable, you need two items: + + 1. You must have a length property. This property should change whenever + the number of items in your enumerable object changes. If you use this + with an `Ember.Object` subclass, you should be sure to change the length + property using `set().` + + 2. You must implement `nextObject().` See documentation. + + Once you have these two methods implemented, apply the `Ember.Enumerable` mixin + to your class and you will be able to enumerate the contents of your object + like any other collection. + + ## Using Ember Enumeration with Other Libraries + + Many other libraries provide some kind of iterator or enumeration like + facility. This is often where the most common API conflicts occur. + Ember's API is designed to be as friendly as possible with other + libraries by implementing only methods that mostly correspond to the + JavaScript 1.8 API. + + @class Enumerable + @namespace Ember + @since Ember 0.9 + */ + __exports__["default"] = Mixin.create({ + + /** + Implement this method to make your class enumerable. + + This method will be call repeatedly during enumeration. The index value + will always begin with 0 and increment monotonically. You don't have to + rely on the index value to determine what object to return, but you should + always check the value and start from the beginning when you see the + requested index is 0. + + The `previousObject` is the object that was returned from the last call + to `nextObject` for the current iteration. This is a useful way to + manage iteration if you are tracing a linked list, for example. + + Finally the context parameter will always contain a hash you can use as + a "scratchpad" to maintain any other state you need in order to iterate + properly. The context object is reused and is not reset between + iterations so make sure you setup the context with a fresh state whenever + the index parameter is 0. + + Generally iterators will continue to call `nextObject` until the index + reaches the your current length-1. If you run out of data before this + time for some reason, you should simply return undefined. + + The default implementation of this method simply looks up the index. + This works great on any Array-like objects. + + @method nextObject + @param {Number} index the current index of the iteration + @param {Object} previousObject the value returned by the last call to + `nextObject`. + @param {Object} context a context object you can use to maintain state. + @return {Object} the next object in the iteration or undefined + */ + nextObject: required(Function), + + /** + Helper method returns the first object from a collection. This is usually + used by bindings and other parts of the framework to extract a single + object if the enumerable contains only one item. + + If you override this method, you should implement it so that it will + always return the same value each time it is called. If your enumerable + contains only one object, this method should always return that object. + If your enumerable is empty, this method should return `undefined`. + + ```javascript + var arr = ["a", "b", "c"]; + arr.get('firstObject'); // "a" + + var arr = []; + arr.get('firstObject'); // undefined + ``` + + @property firstObject + @return {Object} the object or undefined + */ + firstObject: computed('[]', function() { + if (get(this, 'length')===0) return undefined ; + + // handle generic enumerables + var context = popCtx(), ret; + ret = this.nextObject(0, null, context); + pushCtx(context); + return ret; + }), + + /** + Helper method returns the last object from a collection. If your enumerable + contains only one object, this method should always return that object. + If your enumerable is empty, this method should return `undefined`. + + ```javascript + var arr = ["a", "b", "c"]; + arr.get('lastObject'); // "c" + + var arr = []; + arr.get('lastObject'); // undefined + ``` + + @property lastObject + @return {Object} the last object or undefined + */ + lastObject: computed('[]', function() { + var len = get(this, 'length'); + if (len===0) return undefined ; + var context = popCtx(), idx=0, cur, last = null; + do { + last = cur; + cur = this.nextObject(idx++, last, context); + } while (cur !== undefined); + pushCtx(context); + return last; + }), + + /** + Returns `true` if the passed object can be found in the receiver. The + default version will iterate through the enumerable until the object + is found. You may want to override this with a more efficient version. + + ```javascript + var arr = ["a", "b", "c"]; + arr.contains("a"); // true + arr.contains("z"); // false + ``` + + @method contains + @param {Object} obj The object to search for. + @return {Boolean} `true` if object is found in enumerable. + */ + contains: function(obj) { + return this.find(function(item) { return item===obj; }) !== undefined; + }, + + /** + Iterates through the enumerable, calling the passed function on each + item. This method corresponds to the `forEach()` method defined in + JavaScript 1.6. + + The callback method you provide should have the following signature (all + parameters are optional): + + ```javascript + function(item, index, enumerable); + ``` + + - `item` is the current item in the iteration. + - `index` is the current index in the iteration. + - `enumerable` is the enumerable object itself. + + Note that in addition to a callback, you can also pass an optional target + object that will be set as `this` on the context. This is a good way + to give your iterator function access to the current object. + + @method forEach + @param {Function} callback The callback to execute + @param {Object} [target] The target object to use + @return {Object} receiver + */ + forEach: function(callback, target) { + if (typeof callback !== 'function') throw new TypeError() ; + var len = get(this, 'length'), last = null, context = popCtx(); + + if (target === undefined) target = null; + + for(var idx=0;idx1) args = a_slice.call(arguments, 1); + + this.forEach(function(x, idx) { + var method = x && x[methodName]; + if ('function' === typeof method) { + ret[idx] = args ? apply(x, method, args) : x[methodName](); + } + }, this); + + return ret; + }, + + /** + Simply converts the enumerable into a genuine array. The order is not + guaranteed. Corresponds to the method implemented by Prototype. + + @method toArray + @return {Array} the enumerable as an array. + */ + toArray: function() { + var ret = Ember.A(); + this.forEach(function(o, idx) { ret[idx] = o; }); + return ret; + }, + + /** + Returns a copy of the array with all null and undefined elements removed. + + ```javascript + var arr = ["a", null, "c", undefined]; + arr.compact(); // ["a", "c"] + ``` + + @method compact + @return {Array} the array without null and undefined elements. + */ + compact: function() { + return this.filter(function(value) { return value != null; }); + }, + + /** + Returns a new enumerable that excludes the passed value. The default + implementation returns an array regardless of the receiver type unless + the receiver does not contain the value. + + ```javascript + var arr = ["a", "b", "a", "c"]; + arr.without("a"); // ["b", "c"] + ``` + + @method without + @param {Object} value + @return {Ember.Enumerable} + */ + without: function(value) { + if (!this.contains(value)) return this; // nothing to do + var ret = Ember.A(); + this.forEach(function(k) { + if (k !== value) ret[ret.length] = k; + }) ; + return ret ; + }, + + /** + Returns a new enumerable that contains only unique values. The default + implementation returns an array regardless of the receiver type. + + ```javascript + var arr = ["a", "a", "b", "b"]; + arr.uniq(); // ["a", "b"] + ``` + + @method uniq + @return {Ember.Enumerable} + */ + uniq: function() { + var ret = Ember.A(); + this.forEach(function(k) { + if (indexOf(ret, k)<0) ret.push(k); + }); + return ret; + }, + + /** + This property will trigger anytime the enumerable's content changes. + You can observe this property to be notified of changes to the enumerables + content. + + For plain enumerables, this property is read only. `Array` overrides + this method. + + @property [] + @type Array + @return this + */ + '[]': computed(function(key, value) { + return this; + }), + + // .......................................................... + // ENUMERABLE OBSERVERS + // + + /** + Registers an enumerable observer. Must implement `Ember.EnumerableObserver` + mixin. + + @method addEnumerableObserver + @param {Object} target + @param {Hash} [opts] + @return this + */ + addEnumerableObserver: function(target, opts) { + var willChange = (opts && opts.willChange) || 'enumerableWillChange'; + var didChange = (opts && opts.didChange) || 'enumerableDidChange'; + var hasObservers = get(this, 'hasEnumerableObservers'); + + if (!hasObservers) propertyWillChange(this, 'hasEnumerableObservers'); + addListener(this, '@enumerable:before', target, willChange); + addListener(this, '@enumerable:change', target, didChange); + if (!hasObservers) propertyDidChange(this, 'hasEnumerableObservers'); + return this; + }, + + /** + Removes a registered enumerable observer. + + @method removeEnumerableObserver + @param {Object} target + @param {Hash} [opts] + @return this + */ + removeEnumerableObserver: function(target, opts) { + var willChange = (opts && opts.willChange) || 'enumerableWillChange'; + var didChange = (opts && opts.didChange) || 'enumerableDidChange'; + + var hasObservers = get(this, 'hasEnumerableObservers'); + if (hasObservers) propertyWillChange(this, 'hasEnumerableObservers'); + removeListener(this, '@enumerable:before', target, willChange); + removeListener(this, '@enumerable:change', target, didChange); + if (hasObservers) propertyDidChange(this, 'hasEnumerableObservers'); + return this; + }, + + /** + Becomes true whenever the array currently has observers watching changes + on the array. + + @property hasEnumerableObservers + @type Boolean + */ + hasEnumerableObservers: computed(function() { + return hasListeners(this, '@enumerable:change') || hasListeners(this, '@enumerable:before'); + }), + + + /** + Invoke this method just before the contents of your enumerable will + change. You can either omit the parameters completely or pass the objects + to be removed or added if available or just a count. + + @method enumerableContentWillChange + @param {Ember.Enumerable|Number} removing An enumerable of the objects to + be removed or the number of items to be removed. + @param {Ember.Enumerable|Number} adding An enumerable of the objects to be + added or the number of items to be added. + @chainable + */ + enumerableContentWillChange: function(removing, adding) { + + var removeCnt, addCnt, hasDelta; + + if ('number' === typeof removing) removeCnt = removing; + else if (removing) removeCnt = get(removing, 'length'); + else removeCnt = removing = -1; + + if ('number' === typeof adding) addCnt = adding; + else if (adding) addCnt = get(adding,'length'); + else addCnt = adding = -1; + + hasDelta = addCnt<0 || removeCnt<0 || addCnt-removeCnt!==0; + + if (removing === -1) removing = null; + if (adding === -1) adding = null; + + propertyWillChange(this, '[]'); + if (hasDelta) propertyWillChange(this, 'length'); + sendEvent(this, '@enumerable:before', [this, removing, adding]); + + return this; + }, + + /** + Invoke this method when the contents of your enumerable has changed. + This will notify any observers watching for content changes. If you are + implementing an ordered enumerable (such as an array), also pass the + start and end values where the content changed so that it can be used to + notify range observers. + + @method enumerableContentDidChange + @param {Ember.Enumerable|Number} removing An enumerable of the objects to + be removed or the number of items to be removed. + @param {Ember.Enumerable|Number} adding An enumerable of the objects to + be added or the number of items to be added. + @chainable + */ + enumerableContentDidChange: function(removing, adding) { + var removeCnt, addCnt, hasDelta; + + if ('number' === typeof removing) removeCnt = removing; + else if (removing) removeCnt = get(removing, 'length'); + else removeCnt = removing = -1; + + if ('number' === typeof adding) addCnt = adding; + else if (adding) addCnt = get(adding, 'length'); + else addCnt = adding = -1; + + hasDelta = addCnt<0 || removeCnt<0 || addCnt-removeCnt!==0; + + if (removing === -1) removing = null; + if (adding === -1) adding = null; + + sendEvent(this, '@enumerable:change', [this, removing, adding]); + if (hasDelta) propertyDidChange(this, 'length'); + propertyDidChange(this, '[]'); + + return this ; + }, + + /** + Converts the enumerable into an array and sorts by the keys + specified in the argument. + + You may provide multiple arguments to sort by multiple properties. + + @method sortBy + @param {String} property name(s) to sort on + @return {Array} The sorted array. + @since 1.2.0 + */ + sortBy: function() { + var sortKeys = arguments; + return this.toArray().sort(function(a, b){ + for(var i = 0; i < sortKeys.length; i++) { + var key = sortKeys[i]; + var propA = get(a, key); + var propB = get(b, key); + // return 1 or -1 else continue to the next sortKey + var compareValue = compare(propA, propB); + if (compareValue) { return compareValue; } + } + return 0; + }); + } + }); + }); +enifed("ember-runtime/mixins/evented", + ["ember-metal/mixin","ember-metal/events","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Mixin = __dependency1__.Mixin; + var addListener = __dependency2__.addListener; + var removeListener = __dependency2__.removeListener; + var hasListeners = __dependency2__.hasListeners; + var sendEvent = __dependency2__.sendEvent; + + /** + @module ember + @submodule ember-runtime + */ + + /** + This mixin allows for Ember objects to subscribe to and emit events. + + ```javascript + App.Person = Ember.Object.extend(Ember.Evented, { + greet: function() { + // ... + this.trigger('greet'); + } + }); + + var person = App.Person.create(); + + person.on('greet', function() { + console.log('Our person has greeted'); + }); + + person.greet(); + + // outputs: 'Our person has greeted' + ``` + + You can also chain multiple event subscriptions: + + ```javascript + person.on('greet', function() { + console.log('Our person has greeted'); + }).one('greet', function() { + console.log('Offer one-time special'); + }).off('event', this, forgetThis); + ``` + + @class Evented + @namespace Ember + */ + __exports__["default"] = Mixin.create({ + + /** + Subscribes to a named event with given function. + + ```javascript + person.on('didLoad', function() { + // fired once the person has loaded + }); + ``` + + An optional target can be passed in as the 2nd argument that will + be set as the "this" for the callback. This is a good way to give your + function access to the object triggering the event. When the target + parameter is used the callback becomes the third argument. + + @method on + @param {String} name The name of the event + @param {Object} [target] The "this" binding for the callback + @param {Function} method The callback to execute + @return this + */ + on: function(name, target, method) { + addListener(this, name, target, method); + return this; + }, + + /** + Subscribes a function to a named event and then cancels the subscription + after the first time the event is triggered. It is good to use ``one`` when + you only care about the first time an event has taken place. + + This function takes an optional 2nd argument that will become the "this" + value for the callback. If this argument is passed then the 3rd argument + becomes the function. + + @method one + @param {String} name The name of the event + @param {Object} [target] The "this" binding for the callback + @param {Function} method The callback to execute + @return this + */ + one: function(name, target, method) { + if (!method) { + method = target; + target = null; + } + + addListener(this, name, target, method, true); + return this; + }, + + /** + Triggers a named event for the object. Any additional arguments + will be passed as parameters to the functions that are subscribed to the + event. + + ```javascript + person.on('didEat', function(food) { + console.log('person ate some ' + food); + }); + + person.trigger('didEat', 'broccoli'); + + // outputs: person ate some broccoli + ``` + @method trigger + @param {String} name The name of the event + @param {Object...} args Optional arguments to pass on + */ + trigger: function(name) { + var length = arguments.length; + var args = new Array(length - 1); + + for (var i = 1; i < length; i++) { + args[i - 1] = arguments[i]; + } + + sendEvent(this, name, args); + }, + + /** + Cancels subscription for given name, target, and method. + + @method off + @param {String} name The name of the event + @param {Object} target The target of the subscription + @param {Function} method The function of the subscription + @return this + */ + off: function(name, target, method) { + removeListener(this, name, target, method); + return this; + }, + + /** + Checks to see if object has any subscriptions for named event. + + @method has + @param {String} name The name of the event + @return {Boolean} does the object have a subscription for event + */ + has: function(name) { + return hasListeners(this, name); + } + }); + }); +enifed("ember-runtime/mixins/freezable", + ["ember-metal/mixin","ember-metal/property_get","ember-metal/property_set","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Mixin = __dependency1__.Mixin; + var get = __dependency2__.get; + var set = __dependency3__.set; + + /** + The `Ember.Freezable` mixin implements some basic methods for marking an + object as frozen. Once an object is frozen it should be read only. No changes + may be made the internal state of the object. + + ## Enforcement + + To fully support freezing in your subclass, you must include this mixin and + override any method that might alter any property on the object to instead + raise an exception. You can check the state of an object by checking the + `isFrozen` property. + + Although future versions of JavaScript may support language-level freezing + object objects, that is not the case today. Even if an object is freezable, + it is still technically possible to modify the object, even though it could + break other parts of your application that do not expect a frozen object to + change. It is, therefore, very important that you always respect the + `isFrozen` property on all freezable objects. + + ## Example Usage + + The example below shows a simple object that implement the `Ember.Freezable` + protocol. + + ```javascript + Contact = Ember.Object.extend(Ember.Freezable, { + firstName: null, + lastName: null, + + // swaps the names + swapNames: function() { + if (this.get('isFrozen')) throw Ember.FROZEN_ERROR; + var tmp = this.get('firstName'); + this.set('firstName', this.get('lastName')); + this.set('lastName', tmp); + return this; + } + + }); + + c = Contact.create({ firstName: "John", lastName: "Doe" }); + c.swapNames(); // returns c + c.freeze(); + c.swapNames(); // EXCEPTION + ``` + + ## Copying + + Usually the `Ember.Freezable` protocol is implemented in cooperation with the + `Ember.Copyable` protocol, which defines a `frozenCopy()` method that will + return a frozen object, if the object implements this method as well. + + @class Freezable + @namespace Ember + @since Ember 0.9 + */ + var Freezable = Mixin.create({ + + /** + Set to `true` when the object is frozen. Use this property to detect + whether your object is frozen or not. + + @property isFrozen + @type Boolean + */ + isFrozen: false, + + /** + Freezes the object. Once this method has been called the object should + no longer allow any properties to be edited. + + @method freeze + @return {Object} receiver + */ + freeze: function() { + if (get(this, 'isFrozen')) return this; + set(this, 'isFrozen', true); + return this; + } + + }); + __exports__.Freezable = Freezable; + var FROZEN_ERROR = "Frozen object cannot be modified."; + __exports__.FROZEN_ERROR = FROZEN_ERROR; + }); +enifed("ember-runtime/mixins/mutable_array", + ["ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/error","ember-metal/mixin","ember-runtime/mixins/array","ember-runtime/mixins/mutable_enumerable","ember-runtime/mixins/enumerable","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + + // require('ember-runtime/mixins/array'); + // require('ember-runtime/mixins/mutable_enumerable'); + + // .......................................................... + // CONSTANTS + // + + var OUT_OF_RANGE_EXCEPTION = "Index out of range"; + var EMPTY = []; + + // .......................................................... + // HELPERS + // + + var get = __dependency1__.get; + var set = __dependency2__.set; + var isArray = __dependency3__.isArray; + var EmberError = __dependency4__["default"]; + var Mixin = __dependency5__.Mixin; + var required = __dependency5__.required; + var EmberArray = __dependency6__["default"]; + var MutableEnumerable = __dependency7__["default"]; + var Enumerable = __dependency8__["default"]; + /** + This mixin defines the API for modifying array-like objects. These methods + can be applied only to a collection that keeps its items in an ordered set. + It builds upon the Array mixin and adds methods to modify the array. + Concrete implementations of this class include ArrayProxy and ArrayController. + + It is important to use the methods in this class to modify arrays so that + changes are observable. This allows the binding system in Ember to function + correctly. + + + Note that an Array can change even if it does not implement this mixin. + For example, one might implement a SparseArray that cannot be directly + modified, but if its underlying enumerable changes, it will change also. + + @class MutableArray + @namespace Ember + @uses Ember.Array + @uses Ember.MutableEnumerable + */ + __exports__["default"] = Mixin.create(EmberArray, MutableEnumerable, { + + /** + __Required.__ You must implement this method to apply this mixin. + + This is one of the primitives you must implement to support `Ember.Array`. + You should replace amt objects started at idx with the objects in the + passed array. You should also call `this.enumerableContentDidChange()` + + @method replace + @param {Number} idx Starting index in the array to replace. If + idx >= length, then append to the end of the array. + @param {Number} amt Number of elements that should be removed from + the array, starting at *idx*. + @param {Array} objects An array of zero or more objects that should be + inserted into the array at *idx* + */ + replace: required(), + + /** + Remove all elements from the array. This is useful if you + want to reuse an existing array without having to recreate it. + + ```javascript + var colors = ["red", "green", "blue"]; + color.length(); // 3 + colors.clear(); // [] + colors.length(); // 0 + ``` + + @method clear + @return {Ember.Array} An empty Array. + */ + clear: function () { + var len = get(this, 'length'); + if (len === 0) return this; + this.replace(0, len, EMPTY); + return this; + }, + + /** + This will use the primitive `replace()` method to insert an object at the + specified index. + + ```javascript + var colors = ["red", "green", "blue"]; + colors.insertAt(2, "yellow"); // ["red", "green", "yellow", "blue"] + colors.insertAt(5, "orange"); // Error: Index out of range + ``` + + @method insertAt + @param {Number} idx index of insert the object at. + @param {Object} object object to insert + @return {Ember.Array} receiver + */ + insertAt: function(idx, object) { + if (idx > get(this, 'length')) throw new EmberError(OUT_OF_RANGE_EXCEPTION); + this.replace(idx, 0, [object]); + return this; + }, + + /** + Remove an object at the specified index using the `replace()` primitive + method. You can pass either a single index, or a start and a length. + + If you pass a start and length that is beyond the + length this method will throw an `OUT_OF_RANGE_EXCEPTION`. + + ```javascript + var colors = ["red", "green", "blue", "yellow", "orange"]; + colors.removeAt(0); // ["green", "blue", "yellow", "orange"] + colors.removeAt(2, 2); // ["green", "blue"] + colors.removeAt(4, 2); // Error: Index out of range + ``` + + @method removeAt + @param {Number} start index, start of range + @param {Number} len length of passing range + @return {Ember.Array} receiver + */ + removeAt: function(start, len) { + if ('number' === typeof start) { + + if ((start < 0) || (start >= get(this, 'length'))) { + throw new EmberError(OUT_OF_RANGE_EXCEPTION); + } + + // fast case + if (len === undefined) len = 1; + this.replace(start, len, EMPTY); + } + + return this; + }, + + /** + Push the object onto the end of the array. Works just like `push()` but it + is KVO-compliant. + + ```javascript + var colors = ["red", "green"]; + colors.pushObject("black"); // ["red", "green", "black"] + colors.pushObject(["yellow"]); // ["red", "green", ["yellow"]] + ``` + + @method pushObject + @param {*} obj object to push + @return object same object passed as a param + */ + pushObject: function(obj) { + this.insertAt(get(this, 'length'), obj); + return obj; + }, + + /** + Add the objects in the passed numerable to the end of the array. Defers + notifying observers of the change until all objects are added. + + ```javascript + var colors = ["red"]; + colors.pushObjects(["yellow", "orange"]); // ["red", "yellow", "orange"] + ``` + + @method pushObjects + @param {Ember.Enumerable} objects the objects to add + @return {Ember.Array} receiver + */ + pushObjects: function(objects) { + if (!(Enumerable.detect(objects) || isArray(objects))) { + throw new TypeError("Must pass Ember.Enumerable to Ember.MutableArray#pushObjects"); + } + this.replace(get(this, 'length'), 0, objects); + return this; + }, + + /** + Pop object from array or nil if none are left. Works just like `pop()` but + it is KVO-compliant. + + ```javascript + var colors = ["red", "green", "blue"]; + colors.popObject(); // "blue" + console.log(colors); // ["red", "green"] + ``` + + @method popObject + @return object + */ + popObject: function() { + var len = get(this, 'length'); + if (len === 0) return null; + + var ret = this.objectAt(len-1); + this.removeAt(len-1, 1); + return ret; + }, + + /** + Shift an object from start of array or nil if none are left. Works just + like `shift()` but it is KVO-compliant. + + ```javascript + var colors = ["red", "green", "blue"]; + colors.shiftObject(); // "red" + console.log(colors); // ["green", "blue"] + ``` + + @method shiftObject + @return object + */ + shiftObject: function() { + if (get(this, 'length') === 0) return null; + var ret = this.objectAt(0); + this.removeAt(0); + return ret; + }, + + /** + Unshift an object to start of array. Works just like `unshift()` but it is + KVO-compliant. + + ```javascript + var colors = ["red"]; + colors.unshiftObject("yellow"); // ["yellow", "red"] + colors.unshiftObject(["black"]); // [["black"], "yellow", "red"] + ``` + + @method unshiftObject + @param {*} obj object to unshift + @return object same object passed as a param + */ + unshiftObject: function(obj) { + this.insertAt(0, obj); + return obj; + }, + + /** + Adds the named objects to the beginning of the array. Defers notifying + observers until all objects have been added. + + ```javascript + var colors = ["red"]; + colors.unshiftObjects(["black", "white"]); // ["black", "white", "red"] + colors.unshiftObjects("yellow"); // Type Error: 'undefined' is not a function + ``` + + @method unshiftObjects + @param {Ember.Enumerable} objects the objects to add + @return {Ember.Array} receiver + */ + unshiftObjects: function(objects) { + this.replace(0, 0, objects); + return this; + }, + + /** + Reverse objects in the array. Works just like `reverse()` but it is + KVO-compliant. + + @method reverseObjects + @return {Ember.Array} receiver + */ + reverseObjects: function() { + var len = get(this, 'length'); + if (len === 0) return this; + var objects = this.toArray().reverse(); + this.replace(0, len, objects); + return this; + }, + + /** + Replace all the receiver's content with content of the argument. + If argument is an empty array receiver will be cleared. + + ```javascript + var colors = ["red", "green", "blue"]; + colors.setObjects(["black", "white"]); // ["black", "white"] + colors.setObjects([]); // [] + ``` + + @method setObjects + @param {Ember.Array} objects array whose content will be used for replacing + the content of the receiver + @return {Ember.Array} receiver with the new content + */ + setObjects: function(objects) { + if (objects.length === 0) return this.clear(); + + var len = get(this, 'length'); + this.replace(0, len, objects); + return this; + }, + + // .......................................................... + // IMPLEMENT Ember.MutableEnumerable + // + + /** + Remove all occurances of an object in the array. + + ```javascript + var cities = ["Chicago", "Berlin", "Lima", "Chicago"]; + cities.removeObject("Chicago"); // ["Berlin", "Lima"] + cities.removeObject("Lima"); // ["Berlin"] + cities.removeObject("Tokyo") // ["Berlin"] + ``` + + @method removeObject + @param {*} obj object to remove + @return {Ember.Array} receiver + */ + removeObject: function(obj) { + var loc = get(this, 'length') || 0; + while(--loc >= 0) { + var curObject = this.objectAt(loc); + if (curObject === obj) this.removeAt(loc); + } + return this; + }, + + /** + Push the object onto the end of the array if it is not already + present in the array. + + ```javascript + var cities = ["Chicago", "Berlin"]; + cities.addObject("Lima"); // ["Chicago", "Berlin", "Lima"] + cities.addObject("Berlin"); // ["Chicago", "Berlin", "Lima"] + ``` + + @method addObject + @param {*} obj object to add, if not already present + @return {Ember.Array} receiver + */ + addObject: function(obj) { + if (!this.contains(obj)) this.pushObject(obj); + return this; + } + + }); + }); +enifed("ember-runtime/mixins/mutable_enumerable", + ["ember-metal/enumerable_utils","ember-runtime/mixins/enumerable","ember-metal/mixin","ember-metal/property_events","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var forEach = __dependency1__.forEach; + var Enumerable = __dependency2__["default"]; + var Mixin = __dependency3__.Mixin; + var required = __dependency3__.required; + var beginPropertyChanges = __dependency4__.beginPropertyChanges; + var endPropertyChanges = __dependency4__.endPropertyChanges; + + /** + @module ember + @submodule ember-runtime + */ + + /** + This mixin defines the API for modifying generic enumerables. These methods + can be applied to an object regardless of whether it is ordered or + unordered. + + Note that an Enumerable can change even if it does not implement this mixin. + For example, a MappedEnumerable cannot be directly modified but if its + underlying enumerable changes, it will change also. + + ## Adding Objects + + To add an object to an enumerable, use the `addObject()` method. This + method will only add the object to the enumerable if the object is not + already present and is of a type supported by the enumerable. + + ```javascript + set.addObject(contact); + ``` + + ## Removing Objects + + To remove an object from an enumerable, use the `removeObject()` method. This + will only remove the object if it is present in the enumerable, otherwise + this method has no effect. + + ```javascript + set.removeObject(contact); + ``` + + ## Implementing In Your Own Code + + If you are implementing an object and want to support this API, just include + this mixin in your class and implement the required methods. In your unit + tests, be sure to apply the Ember.MutableEnumerableTests to your object. + + @class MutableEnumerable + @namespace Ember + @uses Ember.Enumerable + */ + __exports__["default"] = Mixin.create(Enumerable, { + + /** + __Required.__ You must implement this method to apply this mixin. + + Attempts to add the passed object to the receiver if the object is not + already present in the collection. If the object is present, this method + has no effect. + + If the passed object is of a type not supported by the receiver, + then this method should raise an exception. + + @method addObject + @param {Object} object The object to add to the enumerable. + @return {Object} the passed object + */ + addObject: required(Function), + + /** + Adds each object in the passed enumerable to the receiver. + + @method addObjects + @param {Ember.Enumerable} objects the objects to add. + @return {Object} receiver + */ + addObjects: function(objects) { + beginPropertyChanges(this); + forEach(objects, function(obj) { this.addObject(obj); }, this); + endPropertyChanges(this); + return this; + }, + + /** + __Required.__ You must implement this method to apply this mixin. + + Attempts to remove the passed object from the receiver collection if the + object is present in the collection. If the object is not present, + this method has no effect. + + If the passed object is of a type not supported by the receiver, + then this method should raise an exception. + + @method removeObject + @param {Object} object The object to remove from the enumerable. + @return {Object} the passed object + */ + removeObject: required(Function), + + + /** + Removes each object in the passed enumerable from the receiver. + + @method removeObjects + @param {Ember.Enumerable} objects the objects to remove + @return {Object} receiver + */ + removeObjects: function(objects) { + beginPropertyChanges(this); + for (var i = objects.length - 1; i >= 0; i--) { + this.removeObject(objects[i]); + } + endPropertyChanges(this); + return this; + } + }); + }); +enifed("ember-runtime/mixins/observable", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/get_properties","ember-metal/set_properties","ember-metal/mixin","ember-metal/events","ember-metal/property_events","ember-metal/observer","ember-metal/computed","ember-metal/is_none","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + var Ember = __dependency1__["default"]; + // Ember.assert + + var get = __dependency2__.get; + var getWithDefault = __dependency2__.getWithDefault; + var set = __dependency3__.set; + var apply = __dependency4__.apply; + var getProperties = __dependency5__["default"]; + var setProperties = __dependency6__["default"]; + var Mixin = __dependency7__.Mixin; + var hasListeners = __dependency8__.hasListeners; + var beginPropertyChanges = __dependency9__.beginPropertyChanges; + var propertyWillChange = __dependency9__.propertyWillChange; + var propertyDidChange = __dependency9__.propertyDidChange; + var endPropertyChanges = __dependency9__.endPropertyChanges; + var addObserver = __dependency10__.addObserver; + var addBeforeObserver = __dependency10__.addBeforeObserver; + var removeObserver = __dependency10__.removeObserver; + var observersFor = __dependency10__.observersFor; + var cacheFor = __dependency11__.cacheFor; + var isNone = __dependency12__.isNone; + + + var slice = Array.prototype.slice; + /** + ## Overview + + This mixin provides properties and property observing functionality, core + features of the Ember object model. + + Properties and observers allow one object to observe changes to a + property on another object. This is one of the fundamental ways that + models, controllers and views communicate with each other in an Ember + application. + + Any object that has this mixin applied can be used in observer + operations. That includes `Ember.Object` and most objects you will + interact with as you write your Ember application. + + Note that you will not generally apply this mixin to classes yourself, + but you will use the features provided by this module frequently, so it + is important to understand how to use it. + + ## Using `get()` and `set()` + + Because of Ember's support for bindings and observers, you will always + access properties using the get method, and set properties using the + set method. This allows the observing objects to be notified and + computed properties to be handled properly. + + More documentation about `get` and `set` are below. + + ## Observing Property Changes + + You typically observe property changes simply by adding the `observes` + call to the end of your method declarations in classes that you write. + For example: + + ```javascript + Ember.Object.extend({ + valueObserver: function() { + // Executes whenever the "value" property changes + }.observes('value') + }); + ``` + + Although this is the most common way to add an observer, this capability + is actually built into the `Ember.Object` class on top of two methods + defined in this mixin: `addObserver` and `removeObserver`. You can use + these two methods to add and remove observers yourself if you need to + do so at runtime. + + To add an observer for a property, call: + + ```javascript + object.addObserver('propertyKey', targetObject, targetAction) + ``` + + This will call the `targetAction` method on the `targetObject` whenever + the value of the `propertyKey` changes. + + Note that if `propertyKey` is a computed property, the observer will be + called when any of the property dependencies are changed, even if the + resulting value of the computed property is unchanged. This is necessary + because computed properties are not computed until `get` is called. + + @class Observable + @namespace Ember + */ + __exports__["default"] = Mixin.create({ + + /** + Retrieves the value of a property from the object. + + This method is usually similar to using `object[keyName]` or `object.keyName`, + however it supports both computed properties and the unknownProperty + handler. + + Because `get` unifies the syntax for accessing all these kinds + of properties, it can make many refactorings easier, such as replacing a + simple property with a computed property, or vice versa. + + ### Computed Properties + + Computed properties are methods defined with the `property` modifier + declared at the end, such as: + + ```javascript + fullName: function() { + return this.get('firstName') + ' ' + this.get('lastName'); + }.property('firstName', 'lastName') + ``` + + When you call `get` on a computed property, the function will be + called and the return value will be returned instead of the function + itself. + + ### Unknown Properties + + Likewise, if you try to call `get` on a property whose value is + `undefined`, the `unknownProperty()` method will be called on the object. + If this method returns any value other than `undefined`, it will be returned + instead. This allows you to implement "virtual" properties that are + not defined upfront. + + @method get + @param {String} keyName The property to retrieve + @return {Object} The property value or undefined. + */ + get: function(keyName) { + return get(this, keyName); + }, + + /** + To get the values of multiple properties at once, call `getProperties` + with a list of strings or an array: + + ```javascript + record.getProperties('firstName', 'lastName', 'zipCode'); + // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } + ``` + + is equivalent to: + + ```javascript + record.getProperties(['firstName', 'lastName', 'zipCode']); + // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } + ``` + + @method getProperties + @param {String...|Array} list of keys to get + @return {Hash} + */ + getProperties: function() { + return apply(null, getProperties, [this].concat(slice.call(arguments))); + }, + + /** + Sets the provided key or path to the value. + + This method is generally very similar to calling `object[key] = value` or + `object.key = value`, except that it provides support for computed + properties, the `setUnknownProperty()` method and property observers. + + ### Computed Properties + + If you try to set a value on a key that has a computed property handler + defined (see the `get()` method for an example), then `set()` will call + that method, passing both the value and key instead of simply changing + the value itself. This is useful for those times when you need to + implement a property that is composed of one or more member + properties. + + ### Unknown Properties + + If you try to set a value on a key that is undefined in the target + object, then the `setUnknownProperty()` handler will be called instead. This + gives you an opportunity to implement complex "virtual" properties that + are not predefined on the object. If `setUnknownProperty()` returns + undefined, then `set()` will simply set the value on the object. + + ### Property Observers + + In addition to changing the property, `set()` will also register a property + change with the object. Unless you have placed this call inside of a + `beginPropertyChanges()` and `endPropertyChanges(),` any "local" observers + (i.e. observer methods declared on the same object), will be called + immediately. Any "remote" observers (i.e. observer methods declared on + another object) will be placed in a queue and called at a later time in a + coalesced manner. + + ### Chaining + + In addition to property changes, `set()` returns the value of the object + itself so you can do chaining like this: + + ```javascript + record.set('firstName', 'Charles').set('lastName', 'Jolley'); + ``` + + @method set + @param {String} keyName The property to set + @param {Object} value The value to set or `null`. + @return {Ember.Observable} + */ + set: function(keyName, value) { + set(this, keyName, value); + return this; + }, + + + /** + Sets a list of properties at once. These properties are set inside + a single `beginPropertyChanges` and `endPropertyChanges` batch, so + observers will be buffered. + + ```javascript + record.setProperties({ firstName: 'Charles', lastName: 'Jolley' }); + ``` + + @method setProperties + @param {Hash} hash the hash of keys and values to set + @return {Ember.Observable} + */ + setProperties: function(hash) { + return setProperties(this, hash); + }, + + /** + Begins a grouping of property changes. + + You can use this method to group property changes so that notifications + will not be sent until the changes are finished. If you plan to make a + large number of changes to an object at one time, you should call this + method at the beginning of the changes to begin deferring change + notifications. When you are done making changes, call + `endPropertyChanges()` to deliver the deferred change notifications and end + deferring. + + @method beginPropertyChanges + @return {Ember.Observable} + */ + beginPropertyChanges: function() { + beginPropertyChanges(); + return this; + }, + + /** + Ends a grouping of property changes. + + You can use this method to group property changes so that notifications + will not be sent until the changes are finished. If you plan to make a + large number of changes to an object at one time, you should call + `beginPropertyChanges()` at the beginning of the changes to defer change + notifications. When you are done making changes, call this method to + deliver the deferred change notifications and end deferring. + + @method endPropertyChanges + @return {Ember.Observable} + */ + endPropertyChanges: function() { + endPropertyChanges(); + return this; + }, + + /** + Notify the observer system that a property is about to change. + + Sometimes you need to change a value directly or indirectly without + actually calling `get()` or `set()` on it. In this case, you can use this + method and `propertyDidChange()` instead. Calling these two methods + together will notify all observers that the property has potentially + changed value. + + Note that you must always call `propertyWillChange` and `propertyDidChange` + as a pair. If you do not, it may get the property change groups out of + order and cause notifications to be delivered more often than you would + like. + + @method propertyWillChange + @param {String} keyName The property key that is about to change. + @return {Ember.Observable} + */ + propertyWillChange: function(keyName) { + propertyWillChange(this, keyName); + return this; + }, + + /** + Notify the observer system that a property has just changed. + + Sometimes you need to change a value directly or indirectly without + actually calling `get()` or `set()` on it. In this case, you can use this + method and `propertyWillChange()` instead. Calling these two methods + together will notify all observers that the property has potentially + changed value. + + Note that you must always call `propertyWillChange` and `propertyDidChange` + as a pair. If you do not, it may get the property change groups out of + order and cause notifications to be delivered more often than you would + like. + + @method propertyDidChange + @param {String} keyName The property key that has just changed. + @return {Ember.Observable} + */ + propertyDidChange: function(keyName) { + propertyDidChange(this, keyName); + return this; + }, + + /** + Convenience method to call `propertyWillChange` and `propertyDidChange` in + succession. + + @method notifyPropertyChange + @param {String} keyName The property key to be notified about. + @return {Ember.Observable} + */ + notifyPropertyChange: function(keyName) { + this.propertyWillChange(keyName); + this.propertyDidChange(keyName); + return this; + }, + + addBeforeObserver: function(key, target, method) { + addBeforeObserver(this, key, target, method); + }, + + /** + Adds an observer on a property. + + This is the core method used to register an observer for a property. + + Once you call this method, any time the key's value is set, your observer + will be notified. Note that the observers are triggered any time the + value is set, regardless of whether it has actually changed. Your + observer should be prepared to handle that. + + You can also pass an optional context parameter to this method. The + context will be passed to your observer method whenever it is triggered. + Note that if you add the same target/method pair on a key multiple times + with different context parameters, your observer will only be called once + with the last context you passed. + + ### Observer Methods + + Observer methods you pass should generally have the following signature if + you do not pass a `context` parameter: + + ```javascript + fooDidChange: function(sender, key, value, rev) { }; + ``` + + The sender is the object that changed. The key is the property that + changes. The value property is currently reserved and unused. The rev + is the last property revision of the object when it changed, which you can + use to detect if the key value has really changed or not. + + If you pass a `context` parameter, the context will be passed before the + revision like so: + + ```javascript + fooDidChange: function(sender, key, value, context, rev) { }; + ``` + + Usually you will not need the value, context or revision parameters at + the end. In this case, it is common to write observer methods that take + only a sender and key value as parameters or, if you aren't interested in + any of these values, to write an observer that has no parameters at all. + + @method addObserver + @param {String} key The key to observer + @param {Object} target The target object to invoke + @param {String|Function} method The method to invoke. + */ + addObserver: function(key, target, method) { + addObserver(this, key, target, method); + }, + + /** + Remove an observer you have previously registered on this object. Pass + the same key, target, and method you passed to `addObserver()` and your + target will no longer receive notifications. + + @method removeObserver + @param {String} key The key to observer + @param {Object} target The target object to invoke + @param {String|Function} method The method to invoke. + */ + removeObserver: function(key, target, method) { + removeObserver(this, key, target, method); + }, + + /** + Returns `true` if the object currently has observers registered for a + particular key. You can use this method to potentially defer performing + an expensive action until someone begins observing a particular property + on the object. + + @method hasObserverFor + @param {String} key Key to check + @return {Boolean} + */ + hasObserverFor: function(key) { + return hasListeners(this, key+':change'); + }, + + /** + Retrieves the value of a property, or a default value in the case that the + property returns `undefined`. + + ```javascript + person.getWithDefault('lastName', 'Doe'); + ``` + + @method getWithDefault + @param {String} keyName The name of the property to retrieve + @param {Object} defaultValue The value to return if the property value is undefined + @return {Object} The property value or the defaultValue. + */ + getWithDefault: function(keyName, defaultValue) { + return getWithDefault(this, keyName, defaultValue); + }, + + /** + Set the value of a property to the current value plus some amount. + + ```javascript + person.incrementProperty('age'); + team.incrementProperty('score', 2); + ``` + + @method incrementProperty + @param {String} keyName The name of the property to increment + @param {Number} increment The amount to increment by. Defaults to 1 + @return {Number} The new property value + */ + incrementProperty: function(keyName, increment) { + if (isNone(increment)) { increment = 1; } + set(this, keyName, (parseFloat(get(this, keyName)) || 0) + increment); + return get(this, keyName); + }, + + /** + Set the value of a property to the current value minus some amount. + + ```javascript + player.decrementProperty('lives'); + orc.decrementProperty('health', 5); + ``` + + @method decrementProperty + @param {String} keyName The name of the property to decrement + @param {Number} decrement The amount to decrement by. Defaults to 1 + @return {Number} The new property value + */ + decrementProperty: function(keyName, decrement) { + if (isNone(decrement)) { decrement = 1; } + set(this, keyName, (get(this, keyName) || 0) - decrement); + return get(this, keyName); + }, + + /** + Set the value of a boolean property to the opposite of it's + current value. + + ```javascript + starship.toggleProperty('warpDriveEngaged'); + ``` + + @method toggleProperty + @param {String} keyName The name of the property to toggle + @return {Object} The new property value + */ + toggleProperty: function(keyName) { + set(this, keyName, !get(this, keyName)); + return get(this, keyName); + }, + + /** + Returns the cached value of a computed property, if it exists. + This allows you to inspect the value of a computed property + without accidentally invoking it if it is intended to be + generated lazily. + + @method cacheFor + @param {String} keyName + @return {Object} The cached value of the computed property, if any + */ + cacheFor: function(keyName) { + return cacheFor(this, keyName); + }, + + // intended for debugging purposes + observersForKey: function(keyName) { + return observersFor(this, keyName); + } + }); + }); +enifed("ember-runtime/mixins/promise_proxy", + ["ember-metal/property_get","ember-metal/set_properties","ember-metal/computed","ember-metal/mixin","ember-metal/error","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var setProperties = __dependency2__["default"]; + var computed = __dependency3__.computed; + var Mixin = __dependency4__.Mixin; + var EmberError = __dependency5__["default"]; + + var not = computed.not; + var or = computed.or; + + /** + @module ember + @submodule ember-runtime + */ + + function tap(proxy, promise) { + setProperties(proxy, { + isFulfilled: false, + isRejected: false + }); + + return promise.then(function(value) { + setProperties(proxy, { + content: value, + isFulfilled: true + }); + return value; + }, function(reason) { + setProperties(proxy, { + reason: reason, + isRejected: true + }); + throw reason; + }, "Ember: PromiseProxy"); + } + + /** + A low level mixin making ObjectProxy, ObjectController or ArrayController's promise aware. + + ```javascript + var ObjectPromiseController = Ember.ObjectController.extend(Ember.PromiseProxyMixin); + + var controller = ObjectPromiseController.create({ + promise: $.getJSON('/some/remote/data.json') + }); + + controller.then(function(json){ + // the json + }, function(reason) { + // the reason why you have no json + }); + ``` + + the controller has bindable attributes which + track the promises life cycle + + ```javascript + controller.get('isPending') //=> true + controller.get('isSettled') //=> false + controller.get('isRejected') //=> false + controller.get('isFulfilled') //=> false + ``` + + When the the $.getJSON completes, and the promise is fulfilled + with json, the life cycle attributes will update accordingly. + + ```javascript + controller.get('isPending') //=> false + controller.get('isSettled') //=> true + controller.get('isRejected') //=> false + controller.get('isFulfilled') //=> true + ``` + + As the controller is an ObjectController, and the json now its content, + all the json properties will be available directly from the controller. + + ```javascript + // Assuming the following json: + { + firstName: 'Stefan', + lastName: 'Penner' + } + + // both properties will accessible on the controller + controller.get('firstName') //=> 'Stefan' + controller.get('lastName') //=> 'Penner' + ``` + + If the controller is backing a template, the attributes are + bindable from within that template + + ```handlebars + {{#if isPending}} + loading... + {{else}} + firstName: {{firstName}} + lastName: {{lastName}} + {{/if}} + ``` + @class Ember.PromiseProxyMixin + */ + __exports__["default"] = Mixin.create({ + /** + If the proxied promise is rejected this will contain the reason + provided. + + @property reason + @default null + */ + reason: null, + + /** + Once the proxied promise has settled this will become `false`. + + @property isPending + @default true + */ + isPending: not('isSettled').readOnly(), + + /** + Once the proxied promise has settled this will become `true`. + + @property isSettled + @default false + */ + isSettled: or('isRejected', 'isFulfilled').readOnly(), + + /** + Will become `true` if the proxied promise is rejected. + + @property isRejected + @default false + */ + isRejected: false, + + /** + Will become `true` if the proxied promise is fulfilled. + + @property isFulfilled + @default false + */ + isFulfilled: false, + + /** + The promise whose fulfillment value is being proxied by this object. + + This property must be specified upon creation, and should not be + changed once created. + + Example: + + ```javascript + Ember.ObjectController.extend(Ember.PromiseProxyMixin).create({ + promise: + }); + ``` + + @property promise + */ + promise: computed(function(key, promise) { + if (arguments.length === 2) { + return tap(this, promise); + } else { + throw new EmberError("PromiseProxy's promise must be set"); + } + }), + + /** + An alias to the proxied promise's `then`. + + See RSVP.Promise.then. + + @method then + @param {Function} callback + @return {RSVP.Promise} + */ + then: promiseAlias('then'), + + /** + An alias to the proxied promise's `catch`. + + See RSVP.Promise.catch. + + @method catch + @param {Function} callback + @return {RSVP.Promise} + @since 1.3.0 + */ + 'catch': promiseAlias('catch'), + + /** + An alias to the proxied promise's `finally`. + + See RSVP.Promise.finally. + + @method finally + @param {Function} callback + @return {RSVP.Promise} + @since 1.3.0 + */ + 'finally': promiseAlias('finally') + + }); + + function promiseAlias(name) { + return function () { + var promise = get(this, 'promise'); + return promise[name].apply(promise, arguments); + }; + } + }); +enifed("ember-runtime/mixins/sortable", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/enumerable_utils","ember-metal/mixin","ember-runtime/mixins/mutable_enumerable","ember-runtime/compare","ember-metal/observer","ember-metal/computed","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + // Ember.assert, Ember.A + + var get = __dependency2__.get; + var set = __dependency3__.set; + var forEach = __dependency4__.forEach; + var Mixin = __dependency5__.Mixin; + var MutableEnumerable = __dependency6__["default"]; + var compare = __dependency7__["default"]; + var addObserver = __dependency8__.addObserver; + var removeObserver = __dependency8__.removeObserver; + var computed = __dependency9__.computed; + var beforeObserver = __dependency5__.beforeObserver; + var observer = __dependency5__.observer; + //ES6TODO: should we access these directly from their package or from how thier exposed in ember-metal? + + /** + `Ember.SortableMixin` provides a standard interface for array proxies + to specify a sort order and maintain this sorting when objects are added, + removed, or updated without changing the implicit order of their underlying + modelarray: + + ```javascript + songs = [ + {trackNumber: 4, title: 'Ob-La-Di, Ob-La-Da'}, + {trackNumber: 2, title: 'Back in the U.S.S.R.'}, + {trackNumber: 3, title: 'Glass Onion'}, + ]; + + songsController = Ember.ArrayController.create({ + model: songs, + sortProperties: ['trackNumber'], + sortAscending: true + }); + + songsController.get('firstObject'); // {trackNumber: 2, title: 'Back in the U.S.S.R.'} + + songsController.addObject({trackNumber: 1, title: 'Dear Prudence'}); + songsController.get('firstObject'); // {trackNumber: 1, title: 'Dear Prudence'} + ``` + + If you add or remove the properties to sort by or change the sort direction the model + sort order will be automatically updated. + + ```javascript + songsController.set('sortProperties', ['title']); + songsController.get('firstObject'); // {trackNumber: 2, title: 'Back in the U.S.S.R.'} + + songsController.toggleProperty('sortAscending'); + songsController.get('firstObject'); // {trackNumber: 4, title: 'Ob-La-Di, Ob-La-Da'} + ``` + + SortableMixin works by sorting the arrangedContent array, which is the array that + arrayProxy displays. Due to the fact that the underlying 'content' array is not changed, that + array will not display the sorted list: + + ```javascript + songsController.get('content').get('firstObject'); // Returns the unsorted original content + songsController.get('firstObject'); // Returns the sorted content. + ``` + + Although the sorted content can also be accessed through the arrangedContent property, + it is preferable to use the proxied class and not the arrangedContent array directly. + + @class SortableMixin + @namespace Ember + @uses Ember.MutableEnumerable + */ + __exports__["default"] = Mixin.create(MutableEnumerable, { + + /** + Specifies which properties dictate the arrangedContent's sort order. + + When specifying multiple properties the sorting will use properties + from the `sortProperties` array prioritized from first to last. + + @property {Array} sortProperties + */ + sortProperties: null, + + /** + Specifies the arrangedContent's sort direction. + Sorts the content in ascending order by default. Set to `false` to + use descending order. + + @property {Boolean} sortAscending + @default true + */ + sortAscending: true, + + /** + The function used to compare two values. You can override this if you + want to do custom comparisons. Functions must be of the type expected by + Array#sort, i.e. + return 0 if the two parameters are equal, + return a negative value if the first parameter is smaller than the second or + return a positive value otherwise: + + ```javascript + function(x,y) { // These are assumed to be integers + if (x === y) + return 0; + return x < y ? -1 : 1; + } + ``` + + @property sortFunction + @type {Function} + @default Ember.compare + */ + sortFunction: compare, + + orderBy: function(item1, item2) { + var result = 0; + var sortProperties = get(this, 'sortProperties'); + var sortAscending = get(this, 'sortAscending'); + var sortFunction = get(this, 'sortFunction'); + + + forEach(sortProperties, function(propertyName) { + if (result === 0) { + result = sortFunction.call(this, get(item1, propertyName), get(item2, propertyName)); + if ((result !== 0) && !sortAscending) { + result = (-1) * result; + } + } + }, this); + + return result; + }, + + destroy: function() { + var content = get(this, 'content'); + var sortProperties = get(this, 'sortProperties'); + + if (content && sortProperties) { + forEach(content, function(item) { + forEach(sortProperties, function(sortProperty) { + removeObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + } + + return this._super(); + }, + + isSorted: computed.notEmpty('sortProperties'), + + /** + Overrides the default arrangedContent from arrayProxy in order to sort by sortFunction. + Also sets up observers for each sortProperty on each item in the content Array. + + @property arrangedContent + */ + + arrangedContent: computed('content', 'sortProperties.@each', function(key, value) { + var content = get(this, 'content'); + var isSorted = get(this, 'isSorted'); + var sortProperties = get(this, 'sortProperties'); + var self = this; + + if (content && isSorted) { + content = content.slice(); + content.sort(function(item1, item2) { + return self.orderBy(item1, item2); + }); + forEach(content, function(item) { + forEach(sortProperties, function(sortProperty) { + addObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + return Ember.A(content); + } + + return content; + }), + + _contentWillChange: beforeObserver('content', function() { + var content = get(this, 'content'); + var sortProperties = get(this, 'sortProperties'); + + if (content && sortProperties) { + forEach(content, function(item) { + forEach(sortProperties, function(sortProperty) { + removeObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + } + + this._super(); + }), + + sortPropertiesWillChange: beforeObserver('sortProperties', function() { + this._lastSortAscending = undefined; + }), + + sortPropertiesDidChange: observer('sortProperties', function() { + this._lastSortAscending = undefined; + }), + + sortAscendingWillChange: beforeObserver('sortAscending', function() { + this._lastSortAscending = get(this, 'sortAscending'); + }), + + sortAscendingDidChange: observer('sortAscending', function() { + if (this._lastSortAscending !== undefined && get(this, 'sortAscending') !== this._lastSortAscending) { + var arrangedContent = get(this, 'arrangedContent'); + arrangedContent.reverseObjects(); + } + }), + + contentArrayWillChange: function(array, idx, removedCount, addedCount) { + var isSorted = get(this, 'isSorted'); + + if (isSorted) { + var arrangedContent = get(this, 'arrangedContent'); + var removedObjects = array.slice(idx, idx+removedCount); + var sortProperties = get(this, 'sortProperties'); + + forEach(removedObjects, function(item) { + arrangedContent.removeObject(item); + + forEach(sortProperties, function(sortProperty) { + removeObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + } + + return this._super(array, idx, removedCount, addedCount); + }, + + contentArrayDidChange: function(array, idx, removedCount, addedCount) { + var isSorted = get(this, 'isSorted'); + var sortProperties = get(this, 'sortProperties'); + + if (isSorted) { + var addedObjects = array.slice(idx, idx+addedCount); + + forEach(addedObjects, function(item) { + this.insertItemSorted(item); + + forEach(sortProperties, function(sortProperty) { + addObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + } + + return this._super(array, idx, removedCount, addedCount); + }, + + insertItemSorted: function(item) { + var arrangedContent = get(this, 'arrangedContent'); + var length = get(arrangedContent, 'length'); + + var idx = this._binarySearch(item, 0, length); + arrangedContent.insertAt(idx, item); + }, + + contentItemSortPropertyDidChange: function(item) { + var arrangedContent = get(this, 'arrangedContent'); + var oldIndex = arrangedContent.indexOf(item); + var leftItem = arrangedContent.objectAt(oldIndex - 1); + var rightItem = arrangedContent.objectAt(oldIndex + 1); + var leftResult = leftItem && this.orderBy(item, leftItem); + var rightResult = rightItem && this.orderBy(item, rightItem); + + if (leftResult < 0 || rightResult > 0) { + arrangedContent.removeObject(item); + this.insertItemSorted(item); + } + }, + + _binarySearch: function(item, low, high) { + var mid, midItem, res, arrangedContent; + + if (low === high) { + return low; + } + + arrangedContent = get(this, 'arrangedContent'); + + mid = low + Math.floor((high - low) / 2); + midItem = arrangedContent.objectAt(mid); + + res = this.orderBy(midItem, item); + + if (res < 0) { + return this._binarySearch(item, mid+1, high); + } else if (res > 0) { + return this._binarySearch(item, low, mid); + } + + return mid; + } + }); + }); +enifed("ember-runtime/mixins/target_action_support", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/mixin","ember-metal/computed","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + var Ember = __dependency1__["default"]; + // Ember.lookup, Ember.assert + + var get = __dependency2__.get; + var set = __dependency3__.set; + var typeOf = __dependency4__.typeOf; + var Mixin = __dependency5__.Mixin; + var computed = __dependency6__.computed; + + /** + `Ember.TargetActionSupport` is a mixin that can be included in a class + to add a `triggerAction` method with semantics similar to the Handlebars + `{{action}}` helper. In normal Ember usage, the `{{action}}` helper is + usually the best choice. This mixin is most often useful when you are + doing more complex event handling in View objects. + + See also `Ember.ViewTargetActionSupport`, which has + view-aware defaults for target and actionContext. + + @class TargetActionSupport + @namespace Ember + @extends Ember.Mixin + */ + var TargetActionSupport = Mixin.create({ + target: null, + action: null, + actionContext: null, + + targetObject: computed(function() { + var target = get(this, 'target'); + + if (typeOf(target) === "string") { + var value = get(this, target); + if (value === undefined) { value = get(Ember.lookup, target); } + return value; + } else { + return target; + } + }).property('target'), + + actionContextObject: computed(function() { + var actionContext = get(this, 'actionContext'); + + if (typeOf(actionContext) === "string") { + var value = get(this, actionContext); + if (value === undefined) { value = get(Ember.lookup, actionContext); } + return value; + } else { + return actionContext; + } + }).property('actionContext'), + + /** + Send an `action` with an `actionContext` to a `target`. The action, actionContext + and target will be retrieved from properties of the object. For example: + + ```javascript + App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, { + target: Ember.computed.alias('controller'), + action: 'save', + actionContext: Ember.computed.alias('context'), + click: function() { + this.triggerAction(); // Sends the `save` action, along with the current context + // to the current controller + } + }); + ``` + + The `target`, `action`, and `actionContext` can be provided as properties of + an optional object argument to `triggerAction` as well. + + ```javascript + App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, { + click: function() { + this.triggerAction({ + action: 'save', + target: this.get('controller'), + actionContext: this.get('context') + }); // Sends the `save` action, along with the current context + // to the current controller + } + }); + ``` + + The `actionContext` defaults to the object you are mixing `TargetActionSupport` into. + But `target` and `action` must be specified either as properties or with the argument + to `triggerAction`, or a combination: + + ```javascript + App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, { + target: Ember.computed.alias('controller'), + click: function() { + this.triggerAction({ + action: 'save' + }); // Sends the `save` action, along with a reference to `this`, + // to the current controller + } + }); + ``` + + @method triggerAction + @param opts {Hash} (optional, with the optional keys action, target and/or actionContext) + @return {Boolean} true if the action was sent successfully and did not return false + */ + triggerAction: function(opts) { + opts = opts || {}; + var action = opts.action || get(this, 'action'); + var target = opts.target || get(this, 'targetObject'); + var actionContext = opts.actionContext; + + function args(options, actionName) { + var ret = []; + if (actionName) { ret.push(actionName); } + + return ret.concat(options); + } + + if (typeof actionContext === 'undefined') { + actionContext = get(this, 'actionContextObject') || this; + } + + if (target && action) { + var ret; + + if (target.send) { + ret = target.send.apply(target, args(actionContext, action)); + } else { + ret = target[action].apply(target, args(actionContext)); + } + + if (ret !== false) ret = true; + + return ret; + } else { + return false; + } + } + }); + + __exports__["default"] = TargetActionSupport; + }); +enifed("ember-runtime/system/application", + ["ember-runtime/system/namespace","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Namespace = __dependency1__["default"]; + + __exports__["default"] = Namespace.extend(); + }); +enifed("ember-runtime/system/array_proxy", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/computed","ember-metal/mixin","ember-metal/property_events","ember-metal/error","ember-runtime/system/object","ember-runtime/mixins/mutable_array","ember-runtime/mixins/enumerable","ember-runtime/system/string","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.K, Ember.assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var isArray = __dependency4__.isArray; + var apply = __dependency4__.apply; + var computed = __dependency5__.computed; + var beforeObserver = __dependency6__.beforeObserver; + var observer = __dependency6__.observer; + var beginPropertyChanges = __dependency7__.beginPropertyChanges; + var endPropertyChanges = __dependency7__.endPropertyChanges; + var EmberError = __dependency8__["default"]; + var EmberObject = __dependency9__["default"]; + var MutableArray = __dependency10__["default"]; + var Enumerable = __dependency11__["default"]; + var fmt = __dependency12__.fmt; + + /** + @module ember + @submodule ember-runtime + */ + + var OUT_OF_RANGE_EXCEPTION = "Index out of range"; + var EMPTY = []; + var alias = computed.alias; + var K = Ember.K; + + /** + An ArrayProxy wraps any other object that implements `Ember.Array` and/or + `Ember.MutableArray,` forwarding all requests. This makes it very useful for + a number of binding use cases or other cases where being able to swap + out the underlying array is useful. + + A simple example of usage: + + ```javascript + var pets = ['dog', 'cat', 'fish']; + var ap = Ember.ArrayProxy.create({ content: Ember.A(pets) }); + + ap.get('firstObject'); // 'dog' + ap.set('content', ['amoeba', 'paramecium']); + ap.get('firstObject'); // 'amoeba' + ``` + + This class can also be useful as a layer to transform the contents of + an array, as they are accessed. This can be done by overriding + `objectAtContent`: + + ```javascript + var pets = ['dog', 'cat', 'fish']; + var ap = Ember.ArrayProxy.create({ + content: Ember.A(pets), + objectAtContent: function(idx) { + return this.get('content').objectAt(idx).toUpperCase(); + } + }); + + ap.get('firstObject'); // . 'DOG' + ``` + + @class ArrayProxy + @namespace Ember + @extends Ember.Object + @uses Ember.MutableArray + */ + var ArrayProxy = EmberObject.extend(MutableArray, { + + /** + The content array. Must be an object that implements `Ember.Array` and/or + `Ember.MutableArray.` + + @property content + @type Ember.Array + */ + content: null, + + /** + The array that the proxy pretends to be. In the default `ArrayProxy` + implementation, this and `content` are the same. Subclasses of `ArrayProxy` + can override this property to provide things like sorting and filtering. + + @property arrangedContent + */ + arrangedContent: alias('content'), + + /** + Should actually retrieve the object at the specified index from the + content. You can override this method in subclasses to transform the + content item to something new. + + This method will only be called if content is non-`null`. + + @method objectAtContent + @param {Number} idx The index to retrieve. + @return {Object} the value or undefined if none found + */ + objectAtContent: function(idx) { + return get(this, 'arrangedContent').objectAt(idx); + }, + + /** + Should actually replace the specified objects on the content array. + You can override this method in subclasses to transform the content item + into something new. + + This method will only be called if content is non-`null`. + + @method replaceContent + @param {Number} idx The starting index + @param {Number} amt The number of items to remove from the content. + @param {Array} objects Optional array of objects to insert or null if no + objects. + @return {void} + */ + replaceContent: function(idx, amt, objects) { + get(this, 'content').replace(idx, amt, objects); + }, + + /** + Invoked when the content property is about to change. Notifies observers that the + entire array content will change. + + @private + @method _contentWillChange + */ + _contentWillChange: beforeObserver('content', function() { + this._teardownContent(); + }), + + _teardownContent: function() { + var content = get(this, 'content'); + + if (content) { + content.removeArrayObserver(this, { + willChange: 'contentArrayWillChange', + didChange: 'contentArrayDidChange' + }); + } + }, + + /** + Override to implement content array `willChange` observer. + + @method contentArrayWillChange + + @param {Ember.Array} contentArray the content array + @param {Number} start starting index of the change + @param {Number} removeCount count of items removed + @param {Number} addCount count of items added + + */ + contentArrayWillChange: K, + /** + Override to implement content array `didChange` observer. + + @method contentArrayDidChange + + @param {Ember.Array} contentArray the content array + @param {Number} start starting index of the change + @param {Number} removeCount count of items removed + @param {Number} addCount count of items added + */ + contentArrayDidChange: K, + + /** + Invoked when the content property changes. Notifies observers that the + entire array content has changed. + + @private + @method _contentDidChange + */ + _contentDidChange: observer('content', function() { + var content = get(this, 'content'); + + + this._setupContent(); + }), + + _setupContent: function() { + var content = get(this, 'content'); + + if (content) { + + content.addArrayObserver(this, { + willChange: 'contentArrayWillChange', + didChange: 'contentArrayDidChange' + }); + } + }, + + _arrangedContentWillChange: beforeObserver('arrangedContent', function() { + var arrangedContent = get(this, 'arrangedContent'); + var len = arrangedContent ? get(arrangedContent, 'length') : 0; + + this.arrangedContentArrayWillChange(this, 0, len, undefined); + this.arrangedContentWillChange(this); + + this._teardownArrangedContent(arrangedContent); + }), + + _arrangedContentDidChange: observer('arrangedContent', function() { + var arrangedContent = get(this, 'arrangedContent'); + var len = arrangedContent ? get(arrangedContent, 'length') : 0; + + + this._setupArrangedContent(); + + this.arrangedContentDidChange(this); + this.arrangedContentArrayDidChange(this, 0, undefined, len); + }), + + _setupArrangedContent: function() { + var arrangedContent = get(this, 'arrangedContent'); + + if (arrangedContent) { + + arrangedContent.addArrayObserver(this, { + willChange: 'arrangedContentArrayWillChange', + didChange: 'arrangedContentArrayDidChange' + }); + } + }, + + _teardownArrangedContent: function() { + var arrangedContent = get(this, 'arrangedContent'); + + if (arrangedContent) { + arrangedContent.removeArrayObserver(this, { + willChange: 'arrangedContentArrayWillChange', + didChange: 'arrangedContentArrayDidChange' + }); + } + }, + + arrangedContentWillChange: K, + arrangedContentDidChange: K, + + objectAt: function(idx) { + return get(this, 'content') && this.objectAtContent(idx); + }, + + length: computed(function() { + var arrangedContent = get(this, 'arrangedContent'); + return arrangedContent ? get(arrangedContent, 'length') : 0; + // No dependencies since Enumerable notifies length of change + }), + + _replace: function(idx, amt, objects) { + var content = get(this, 'content'); + if (content) this.replaceContent(idx, amt, objects); + return this; + }, + + replace: function() { + if (get(this, 'arrangedContent') === get(this, 'content')) { + apply(this, this._replace, arguments); + } else { + throw new EmberError("Using replace on an arranged ArrayProxy is not allowed."); + } + }, + + _insertAt: function(idx, object) { + if (idx > get(this, 'content.length')) throw new EmberError(OUT_OF_RANGE_EXCEPTION); + this._replace(idx, 0, [object]); + return this; + }, + + insertAt: function(idx, object) { + if (get(this, 'arrangedContent') === get(this, 'content')) { + return this._insertAt(idx, object); + } else { + throw new EmberError("Using insertAt on an arranged ArrayProxy is not allowed."); + } + }, + + removeAt: function(start, len) { + if ('number' === typeof start) { + var content = get(this, 'content'); + var arrangedContent = get(this, 'arrangedContent'); + var indices = []; + var i; + + if ((start < 0) || (start >= get(this, 'length'))) { + throw new EmberError(OUT_OF_RANGE_EXCEPTION); + } + + if (len === undefined) len = 1; + + // Get a list of indices in original content to remove + for (i=start; i= 0) { + var baseValue = this[keyName]; + + if (baseValue) { + if ('function' === typeof baseValue.concat) { + value = baseValue.concat(value); + } else { + value = makeArray(baseValue).concat(value); + } + } else { + value = makeArray(value); + } + } + + if (desc) { + desc.set(this, keyName, value); + } else { + if (typeof this.setUnknownProperty === 'function' && !(keyName in this)) { + this.setUnknownProperty(keyName, value); + } else { + + this[keyName] = value; + + } + } + } + } + } + finishPartial(this, m); + var length = arguments.length; + var args = new Array(length); + for (var x = 0; x < length; x++) { + args[x] = arguments[x]; + } + apply(this, this.init, args); + m.proto = proto; + finishChains(this); + sendEvent(this, "init"); + }; + + Class.toString = Mixin.prototype.toString; + Class.willReopen = function() { + if (wasApplied) { + Class.PrototypeMixin = Mixin.create(Class.PrototypeMixin); + } + + wasApplied = false; + }; + Class._initMixins = function(args) { initMixins = args; }; + Class._initProperties = function(args) { initProperties = args; }; + + Class.proto = function() { + var superclass = Class.superclass; + if (superclass) { superclass.proto(); } + + if (!wasApplied) { + wasApplied = true; + Class.PrototypeMixin.applyPartial(Class.prototype); + rewatch(Class.prototype); + } + + return this.prototype; + }; + + return Class; + + } + + /** + @class CoreObject + @namespace Ember + */ + var CoreObject = makeCtor(); + CoreObject.toString = function() { return "Ember.CoreObject"; }; + CoreObject.PrototypeMixin = Mixin.create({ + reopen: function() { + var length = arguments.length; + var args = new Array(length); + for (var i = 0; i < length; i++) { + args[i] = arguments[i]; + } + applyMixin(this, args, true); + return this; + }, + + /** + An overridable method called when objects are instantiated. By default, + does nothing unless it is overridden during class definition. + + Example: + + ```javascript + App.Person = Ember.Object.extend({ + init: function() { + alert('Name is ' + this.get('name')); + } + }); + + var steve = App.Person.create({ + name: "Steve" + }); + + // alerts 'Name is Steve'. + ``` + + NOTE: If you do override `init` for a framework class like `Ember.View` or + `Ember.ArrayController`, be sure to call `this._super()` in your + `init` declaration! If you don't, Ember may not have an opportunity to + do important setup work, and you'll see strange behavior in your + application. + + @method init + */ + init: function() {}, + + /** + Defines the properties that will be concatenated from the superclass + (instead of overridden). + + By default, when you extend an Ember class a property defined in + the subclass overrides a property with the same name that is defined + in the superclass. However, there are some cases where it is preferable + to build up a property's value by combining the superclass' property + value with the subclass' value. An example of this in use within Ember + is the `classNames` property of `Ember.View`. + + Here is some sample code showing the difference between a concatenated + property and a normal one: + + ```javascript + App.BarView = Ember.View.extend({ + someNonConcatenatedProperty: ['bar'], + classNames: ['bar'] + }); + + App.FooBarView = App.BarView.extend({ + someNonConcatenatedProperty: ['foo'], + classNames: ['foo'] + }); + + var fooBarView = App.FooBarView.create(); + fooBarView.get('someNonConcatenatedProperty'); // ['foo'] + fooBarView.get('classNames'); // ['ember-view', 'bar', 'foo'] + ``` + + This behavior extends to object creation as well. Continuing the + above example: + + ```javascript + var view = App.FooBarView.create({ + someNonConcatenatedProperty: ['baz'], + classNames: ['baz'] + }) + view.get('someNonConcatenatedProperty'); // ['baz'] + view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz'] + ``` + Adding a single property that is not an array will just add it in the array: + + ```javascript + var view = App.FooBarView.create({ + classNames: 'baz' + }) + view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz'] + ``` + + Using the `concatenatedProperties` property, we can tell to Ember that mix + the content of the properties. + + In `Ember.View` the `classNameBindings` and `attributeBindings` properties + are also concatenated, in addition to `classNames`. + + This feature is available for you to use throughout the Ember object model, + although typical app developers are likely to use it infrequently. Since + it changes expectations about behavior of properties, you should properly + document its usage in each individual concatenated property (to not + mislead your users to think they can override the property in a subclass). + + @property concatenatedProperties + @type Array + @default null + */ + concatenatedProperties: null, + + /** + Destroyed object property flag. + + if this property is `true` the observers and bindings were already + removed by the effect of calling the `destroy()` method. + + @property isDestroyed + @default false + */ + isDestroyed: false, + + /** + Destruction scheduled flag. The `destroy()` method has been called. + + The object stays intact until the end of the run loop at which point + the `isDestroyed` flag is set. + + @property isDestroying + @default false + */ + isDestroying: false, + + /** + Destroys an object by setting the `isDestroyed` flag and removing its + metadata, which effectively destroys observers and bindings. + + If you try to set a property on a destroyed object, an exception will be + raised. + + Note that destruction is scheduled for the end of the run loop and does not + happen immediately. It will set an isDestroying flag immediately. + + @method destroy + @return {Ember.Object} receiver + */ + destroy: function() { + if (this.isDestroying) { return; } + this.isDestroying = true; + + schedule('actions', this, this.willDestroy); + schedule('destroy', this, this._scheduledDestroy); + return this; + }, + + /** + Override to implement teardown. + + @method willDestroy + */ + willDestroy: K, + + /** + Invoked by the run loop to actually destroy the object. This is + scheduled for execution by the `destroy` method. + + @private + @method _scheduledDestroy + */ + _scheduledDestroy: function() { + if (this.isDestroyed) { return; } + destroy(this); + this.isDestroyed = true; + }, + + bind: function(to, from) { + if (!(from instanceof Binding)) { from = Binding.from(from); } + from.to(to).connect(this); + return from; + }, + + /** + Returns a string representation which attempts to provide more information + than Javascript's `toString` typically does, in a generic way for all Ember + objects. + + ```javascript + App.Person = Em.Object.extend() + person = App.Person.create() + person.toString() //=> "" + ``` + + If the object's class is not defined on an Ember namespace, it will + indicate it is a subclass of the registered superclass: + + ```javascript + Student = App.Person.extend() + student = Student.create() + student.toString() //=> "<(subclass of App.Person):ember1025>" + ``` + + If the method `toStringExtension` is defined, its return value will be + included in the output. + + ```javascript + App.Teacher = App.Person.extend({ + toStringExtension: function() { + return this.get('fullName'); + } + }); + teacher = App.Teacher.create() + teacher.toString(); //=> "" + ``` + + @method toString + @return {String} string representation + */ + toString: function toString() { + var hasToStringExtension = typeof this.toStringExtension === 'function'; + var extension = hasToStringExtension ? ":" + this.toStringExtension() : ''; + var ret = '<'+this.constructor.toString()+':'+guidFor(this)+extension+'>'; + + this.toString = makeToString(ret); + return ret; + } + }); + + CoreObject.PrototypeMixin.ownerConstructor = CoreObject; + + function makeToString(ret) { + return function() { return ret; }; + } + + if (Ember.config.overridePrototypeMixin) { + Ember.config.overridePrototypeMixin(CoreObject.PrototypeMixin); + } + + CoreObject.__super__ = null; + + var ClassMixin = Mixin.create({ + + ClassMixin: required(), + + PrototypeMixin: required(), + + isClass: true, + + isMethod: false, + + /** + Creates a new subclass. + + ```javascript + App.Person = Ember.Object.extend({ + say: function(thing) { + alert(thing); + } + }); + ``` + + This defines a new subclass of Ember.Object: `App.Person`. It contains one method: `say()`. + + You can also create a subclass from any existing class by calling its `extend()` method. For example, you might want to create a subclass of Ember's built-in `Ember.View` class: + + ```javascript + App.PersonView = Ember.View.extend({ + tagName: 'li', + classNameBindings: ['isAdministrator'] + }); + ``` + + When defining a subclass, you can override methods but still access the implementation of your parent class by calling the special `_super()` method: + + ```javascript + App.Person = Ember.Object.extend({ + say: function(thing) { + var name = this.get('name'); + alert(name + ' says: ' + thing); + } + }); + + App.Soldier = App.Person.extend({ + say: function(thing) { + this._super(thing + ", sir!"); + }, + march: function(numberOfHours) { + alert(this.get('name') + ' marches for ' + numberOfHours + ' hours.') + } + }); + + var yehuda = App.Soldier.create({ + name: "Yehuda Katz" + }); + + yehuda.say("Yes"); // alerts "Yehuda Katz says: Yes, sir!" + ``` + + The `create()` on line #17 creates an *instance* of the `App.Soldier` class. The `extend()` on line #8 creates a *subclass* of `App.Person`. Any instance of the `App.Person` class will *not* have the `march()` method. + + You can also pass `Mixin` classes to add additional properties to the subclass. + + ```javascript + App.Person = Ember.Object.extend({ + say: function(thing) { + alert(this.get('name') + ' says: ' + thing); + } + }); + + App.SingingMixin = Mixin.create({ + sing: function(thing){ + alert(this.get('name') + ' sings: la la la ' + thing); + } + }); + + App.BroadwayStar = App.Person.extend(App.SingingMixin, { + dance: function() { + alert(this.get('name') + ' dances: tap tap tap tap '); + } + }); + ``` + + The `App.BroadwayStar` class contains three methods: `say()`, `sing()`, and `dance()`. + + @method extend + @static + + @param {Mixin} [mixins]* One or more Mixin classes + @param {Object} [arguments]* Object containing values to use within the new class + */ + extend: function extend() { + var Class = makeCtor(); + var proto; + Class.ClassMixin = Mixin.create(this.ClassMixin); + Class.PrototypeMixin = Mixin.create(this.PrototypeMixin); + + Class.ClassMixin.ownerConstructor = Class; + Class.PrototypeMixin.ownerConstructor = Class; + + reopen.apply(Class.PrototypeMixin, arguments); + + Class.superclass = this; + Class.__super__ = this.prototype; + + proto = Class.prototype = o_create(this.prototype); + proto.constructor = Class; + generateGuid(proto); + meta(proto).proto = proto; // this will disable observers on prototype + + Class.ClassMixin.apply(Class); + return Class; + }, + + /** + Equivalent to doing `extend(arguments).create()`. + If possible use the normal `create` method instead. + + @method createWithMixins + @static + @param [arguments]* + */ + createWithMixins: function() { + var C = this; + var l= arguments.length; + if (l > 0) { + var args = new Array(l); + for (var i = 0; i < l; i++) { + args[i] = arguments[i]; + } + this._initMixins(args); + } + return new C(); + }, + + /** + Creates an instance of a class. Accepts either no arguments, or an object + containing values to initialize the newly instantiated object with. + + ```javascript + App.Person = Ember.Object.extend({ + helloWorld: function() { + alert("Hi, my name is " + this.get('name')); + } + }); + + var tom = App.Person.create({ + name: 'Tom Dale' + }); + + tom.helloWorld(); // alerts "Hi, my name is Tom Dale". + ``` + + `create` will call the `init` function if defined during + `Ember.AnyObject.extend` + + If no arguments are passed to `create`, it will not set values to the new + instance during initialization: + + ```javascript + var noName = App.Person.create(); + noName.helloWorld(); // alerts undefined + ``` + + NOTE: For performance reasons, you cannot declare methods or computed + properties during `create`. You should instead declare methods and computed + properties when using `extend` or use the `createWithMixins` shorthand. + + @method create + @static + @param [arguments]* + */ + create: function() { + var C = this; + var l = arguments.length; + if (l > 0) { + var args = new Array(l); + for (var i = 0; i < l; i++) { + args[i] = arguments[i]; + } + this._initProperties(args); + } + return new C(); + }, + + /** + Augments a constructor's prototype with additional + properties and functions: + + ```javascript + MyObject = Ember.Object.extend({ + name: 'an object' + }); + + o = MyObject.create(); + o.get('name'); // 'an object' + + MyObject.reopen({ + say: function(msg){ + console.log(msg); + } + }) + + o2 = MyObject.create(); + o2.say("hello"); // logs "hello" + + o.say("goodbye"); // logs "goodbye" + ``` + + To add functions and properties to the constructor itself, + see `reopenClass` + + @method reopen + */ + reopen: function() { + this.willReopen(); + + var l = arguments.length; + var args = new Array(l); + if (l > 0) { + for (var i = 0; i < l; i++) { + args[i] = arguments[i]; + } + } + + apply(this.PrototypeMixin, reopen, args); + return this; + }, + + /** + Augments a constructor's own properties and functions: + + ```javascript + MyObject = Ember.Object.extend({ + name: 'an object' + }); + + MyObject.reopenClass({ + canBuild: false + }); + + MyObject.canBuild; // false + o = MyObject.create(); + ``` + + In other words, this creates static properties and functions for the class. These are only available on the class + and not on any instance of that class. + + ```javascript + App.Person = Ember.Object.extend({ + name : "", + sayHello : function(){ + alert("Hello. My name is " + this.get('name')); + } + }); + + App.Person.reopenClass({ + species : "Homo sapiens", + createPerson: function(newPersonsName){ + return App.Person.create({ + name:newPersonsName + }); + } + }); + + var tom = App.Person.create({ + name : "Tom Dale" + }); + var yehuda = App.Person.createPerson("Yehuda Katz"); + + tom.sayHello(); // "Hello. My name is Tom Dale" + yehuda.sayHello(); // "Hello. My name is Yehuda Katz" + alert(App.Person.species); // "Homo sapiens" + ``` + + Note that `species` and `createPerson` are *not* valid on the `tom` and `yehuda` + variables. They are only valid on `App.Person`. + + To add functions and properties to instances of + a constructor by extending the constructor's prototype + see `reopen` + + @method reopenClass + */ + reopenClass: function() { + var l = arguments.length; + var args = new Array(l); + if (l > 0) { + for (var i = 0; i < l; i++) { + args[i] = arguments[i]; + } + } + + apply(this.ClassMixin, reopen, args); + applyMixin(this, arguments, false); + return this; + }, + + detect: function(obj) { + if ('function' !== typeof obj) { return false; } + while(obj) { + if (obj===this) { return true; } + obj = obj.superclass; + } + return false; + }, + + detectInstance: function(obj) { + return obj instanceof this; + }, + + /** + In some cases, you may want to annotate computed properties with additional + metadata about how they function or what values they operate on. For + example, computed property functions may close over variables that are then + no longer available for introspection. + + You can pass a hash of these values to a computed property like this: + + ```javascript + person: function() { + var personId = this.get('personId'); + return App.Person.create({ id: personId }); + }.property().meta({ type: App.Person }) + ``` + + Once you've done this, you can retrieve the values saved to the computed + property from your class like this: + + ```javascript + MyClass.metaForProperty('person'); + ``` + + This will return the original hash that was passed to `meta()`. + + @method metaForProperty + @param key {String} property name + */ + metaForProperty: function(key) { + var meta = this.proto()['__ember_meta__']; + var desc = meta && meta.descs[key]; + + return desc._meta || {}; + }, + + _computedProperties: Ember.computed(function() { + hasCachedComputedProperties = true; + var proto = this.proto(); + var descs = meta(proto).descs; + var property; + var properties = []; + + for (var name in descs) { + property = descs[name]; + + if (property instanceof ComputedProperty) { + properties.push({ + name: name, + meta: property._meta + }); + } + } + return properties; + }).readOnly(), + + /** + Iterate over each computed property for the class, passing its name + and any associated metadata (see `metaForProperty`) to the callback. + + @method eachComputedProperty + @param {Function} callback + @param {Object} binding + */ + eachComputedProperty: function(callback, binding) { + var property, name; + var empty = {}; + + var properties = get(this, '_computedProperties'); + + for (var i = 0, length = properties.length; i < length; i++) { + property = properties[i]; + name = property.name; + callback.call(binding || this, property.name, property.meta || empty); + } + } + }); + + ClassMixin.ownerConstructor = CoreObject; + + if (Ember.config.overrideClassMixin) { + Ember.config.overrideClassMixin(ClassMixin); + } + + CoreObject.ClassMixin = ClassMixin; + + ClassMixin.apply(CoreObject); + + CoreObject.reopen({ + didDefineProperty: function(proto, key, value) { + if (hasCachedComputedProperties === false) { return; } + if (value instanceof Ember.ComputedProperty) { + var cache = Ember.meta(this.constructor).cache; + + if (cache._computedProperties !== undefined) { + cache._computedProperties = undefined; + } + } + } + }); + + __exports__["default"] = CoreObject; + }); +enifed("ember-runtime/system/deferred", + ["ember-metal/core","ember-runtime/mixins/deferred","ember-metal/property_get","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var DeferredMixin = __dependency2__["default"]; + var get = __dependency3__.get; + var EmberObject = __dependency4__["default"]; + + var Deferred = EmberObject.extend(DeferredMixin, { + init: function() { + this._super(); + } + }); + + Deferred.reopenClass({ + promise: function(callback, binding) { + var deferred = Deferred.create(); + callback.call(binding, deferred); + return deferred; + } + }); + + __exports__["default"] = Deferred; + }); +enifed("ember-runtime/system/each_proxy", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/enumerable_utils","ember-metal/array","ember-runtime/mixins/array","ember-runtime/system/object","ember-metal/computed","ember-metal/observer","ember-metal/events","ember-metal/properties","ember-metal/property_events","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + // Ember.assert + + var get = __dependency2__.get; + var set = __dependency3__.set; + var guidFor = __dependency4__.guidFor; + var forEach = __dependency5__.forEach; + var indexOf = __dependency6__.indexOf; + var EmberArray = __dependency7__["default"]; + // ES6TODO: WAT? Circular dep? + var EmberObject = __dependency8__["default"]; + var computed = __dependency9__.computed; + var addObserver = __dependency10__.addObserver; + var addBeforeObserver = __dependency10__.addBeforeObserver; + var removeBeforeObserver = __dependency10__.removeBeforeObserver; + var removeObserver = __dependency10__.removeObserver; + var typeOf = __dependency4__.typeOf; + var watchedEvents = __dependency11__.watchedEvents; + var defineProperty = __dependency12__.defineProperty; + var beginPropertyChanges = __dependency13__.beginPropertyChanges; + var propertyDidChange = __dependency13__.propertyDidChange; + var propertyWillChange = __dependency13__.propertyWillChange; + var endPropertyChanges = __dependency13__.endPropertyChanges; + var changeProperties = __dependency13__.changeProperties; + + var EachArray = EmberObject.extend(EmberArray, { + + init: function(content, keyName, owner) { + this._super(); + this._keyName = keyName; + this._owner = owner; + this._content = content; + }, + + objectAt: function(idx) { + var item = this._content.objectAt(idx); + return item && get(item, this._keyName); + }, + + length: computed(function() { + var content = this._content; + return content ? get(content, 'length') : 0; + }) + + }); + + var IS_OBSERVER = /^.+:(before|change)$/; + + function addObserverForContentKey(content, keyName, proxy, idx, loc) { + var objects = proxy._objects; + var guid; + if (!objects) objects = proxy._objects = {}; + + while(--loc>=idx) { + var item = content.objectAt(loc); + if (item) { + addBeforeObserver(item, keyName, proxy, 'contentKeyWillChange'); + addObserver(item, keyName, proxy, 'contentKeyDidChange'); + + // keep track of the index each item was found at so we can map + // it back when the obj changes. + guid = guidFor(item); + if (!objects[guid]) objects[guid] = []; + objects[guid].push(loc); + } + } + } + + function removeObserverForContentKey(content, keyName, proxy, idx, loc) { + var objects = proxy._objects; + if (!objects) objects = proxy._objects = {}; + var indicies, guid; + + while(--loc>=idx) { + var item = content.objectAt(loc); + if (item) { + removeBeforeObserver(item, keyName, proxy, 'contentKeyWillChange'); + removeObserver(item, keyName, proxy, 'contentKeyDidChange'); + + guid = guidFor(item); + indicies = objects[guid]; + indicies[indexOf.call(indicies, loc)] = null; + } + } + } + + /** + This is the object instance returned when you get the `@each` property on an + array. It uses the unknownProperty handler to automatically create + EachArray instances for property names. + + @private + @class EachProxy + @namespace Ember + @extends Ember.Object + */ + var EachProxy = EmberObject.extend({ + + init: function(content) { + this._super(); + this._content = content; + content.addArrayObserver(this); + + // in case someone is already observing some keys make sure they are + // added + forEach(watchedEvents(this), function(eventName) { + this.didAddListener(eventName); + }, this); + }, + + /** + You can directly access mapped properties by simply requesting them. + The `unknownProperty` handler will generate an EachArray of each item. + + @method unknownProperty + @param keyName {String} + @param value {*} + */ + unknownProperty: function(keyName, value) { + var ret; + ret = new EachArray(this._content, keyName, this); + defineProperty(this, keyName, null, ret); + this.beginObservingContentKey(keyName); + return ret; + }, + + // .......................................................... + // ARRAY CHANGES + // Invokes whenever the content array itself changes. + + arrayWillChange: function(content, idx, removedCnt, addedCnt) { + var keys = this._keys; + var key, lim; + + lim = removedCnt>0 ? idx+removedCnt : -1; + beginPropertyChanges(this); + + for(key in keys) { + if (!keys.hasOwnProperty(key)) { continue; } + + if (lim>0) { removeObserverForContentKey(content, key, this, idx, lim); } + + propertyWillChange(this, key); + } + + propertyWillChange(this._content, '@each'); + endPropertyChanges(this); + }, + + arrayDidChange: function(content, idx, removedCnt, addedCnt) { + var keys = this._keys; + var lim; + + lim = addedCnt>0 ? idx+addedCnt : -1; + changeProperties(function() { + for(var key in keys) { + if (!keys.hasOwnProperty(key)) { continue; } + + if (lim>0) { addObserverForContentKey(content, key, this, idx, lim); } + + propertyDidChange(this, key); + } + + propertyDidChange(this._content, '@each'); + }, this); + }, + + // .......................................................... + // LISTEN FOR NEW OBSERVERS AND OTHER EVENT LISTENERS + // Start monitoring keys based on who is listening... + + didAddListener: function(eventName) { + if (IS_OBSERVER.test(eventName)) { + this.beginObservingContentKey(eventName.slice(0, -7)); + } + }, + + didRemoveListener: function(eventName) { + if (IS_OBSERVER.test(eventName)) { + this.stopObservingContentKey(eventName.slice(0, -7)); + } + }, + + // .......................................................... + // CONTENT KEY OBSERVING + // Actual watch keys on the source content. + + beginObservingContentKey: function(keyName) { + var keys = this._keys; + if (!keys) keys = this._keys = {}; + if (!keys[keyName]) { + keys[keyName] = 1; + var content = this._content; + var len = get(content, 'length'); + + addObserverForContentKey(content, keyName, this, 0, len); + } else { + keys[keyName]++; + } + }, + + stopObservingContentKey: function(keyName) { + var keys = this._keys; + if (keys && (keys[keyName]>0) && (--keys[keyName]<=0)) { + var content = this._content; + var len = get(content, 'length'); + + removeObserverForContentKey(content, keyName, this, 0, len); + } + }, + + contentKeyWillChange: function(obj, keyName) { + propertyWillChange(this, keyName); + }, + + contentKeyDidChange: function(obj, keyName) { + propertyDidChange(this, keyName); + } + }); + + __exports__.EachArray = EachArray; + __exports__.EachProxy = EachProxy; + }); +enifed("ember-runtime/system/lazy_load", + ["ember-metal/core","ember-metal/array","ember-runtime/system/native_array","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + /*globals CustomEvent */ + + var Ember = __dependency1__["default"]; + // Ember.ENV.EMBER_LOAD_HOOKS + var forEach = __dependency2__.forEach; + // make sure Ember.A is setup. + + /** + @module ember + @submodule ember-runtime + */ + + var loadHooks = Ember.ENV.EMBER_LOAD_HOOKS || {}; + var loaded = {}; + + /** + Detects when a specific package of Ember (e.g. 'Ember.Handlebars') + has fully loaded and is available for extension. + + The provided `callback` will be called with the `name` passed + resolved from a string into the object: + + ``` javascript + Ember.onLoad('Ember.Handlebars' function(hbars) { + hbars.registerHelper(...); + }); + ``` + + @method onLoad + @for Ember + @param name {String} name of hook + @param callback {Function} callback to be called + */ + function onLoad(name, callback) { + var object; + + loadHooks[name] = loadHooks[name] || Ember.A(); + loadHooks[name].pushObject(callback); + + if (object = loaded[name]) { + callback(object); + } + } + + __exports__.onLoad = onLoad;/** + Called when an Ember.js package (e.g Ember.Handlebars) has finished + loading. Triggers any callbacks registered for this event. + + @method runLoadHooks + @for Ember + @param name {String} name of hook + @param object {Object} object to pass to callbacks + */ + function runLoadHooks(name, object) { + loaded[name] = object; + + if (typeof window === 'object' && typeof window.dispatchEvent === 'function' && typeof CustomEvent === "function") { + var event = new CustomEvent(name, {detail: object, name: name}); + window.dispatchEvent(event); + } + + if (loadHooks[name]) { + forEach.call(loadHooks[name], function(callback) { + callback(object); + }); + } + } + + __exports__.runLoadHooks = runLoadHooks; + }); +enifed("ember-runtime/system/namespace", + ["ember-metal/core","ember-metal/property_get","ember-metal/array","ember-metal/utils","ember-metal/mixin","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + // Ember.lookup, Ember.BOOTED, Ember.deprecate, Ember.NAME_KEY, Ember.anyUnprocessedMixins + var Ember = __dependency1__["default"]; + var get = __dependency2__.get; + var indexOf = __dependency3__.indexOf; + var GUID_KEY = __dependency4__.GUID_KEY; + var guidFor = __dependency4__.guidFor; + var Mixin = __dependency5__.Mixin; + + var EmberObject = __dependency6__["default"]; + + /** + A Namespace is an object usually used to contain other objects or methods + such as an application or framework. Create a namespace anytime you want + to define one of these new containers. + + # Example Usage + + ```javascript + MyFramework = Ember.Namespace.create({ + VERSION: '1.0.0' + }); + ``` + + @class Namespace + @namespace Ember + @extends Ember.Object + */ + var Namespace = EmberObject.extend({ + isNamespace: true, + + init: function() { + Namespace.NAMESPACES.push(this); + Namespace.PROCESSED = false; + }, + + toString: function() { + var name = get(this, 'name') || get(this, 'modulePrefix'); + if (name) { return name; } + + findNamespaces(); + return this[NAME_KEY]; + }, + + nameClasses: function() { + processNamespace([this.toString()], this, {}); + }, + + destroy: function() { + var namespaces = Namespace.NAMESPACES; + var toString = this.toString(); + + if (toString) { + Ember.lookup[toString] = undefined; + delete Namespace.NAMESPACES_BY_ID[toString]; + } + namespaces.splice(indexOf.call(namespaces, this), 1); + this._super(); + } + }); + + Namespace.reopenClass({ + NAMESPACES: [Ember], + NAMESPACES_BY_ID: {}, + PROCESSED: false, + processAll: processAllNamespaces, + byName: function(name) { + if (!Ember.BOOTED) { + processAllNamespaces(); + } + + return NAMESPACES_BY_ID[name]; + } + }); + + var NAMESPACES_BY_ID = Namespace.NAMESPACES_BY_ID; + + var hasOwnProp = ({}).hasOwnProperty; + + function processNamespace(paths, root, seen) { + var idx = paths.length; + + NAMESPACES_BY_ID[paths.join('.')] = root; + + // Loop over all of the keys in the namespace, looking for classes + for(var key in root) { + if (!hasOwnProp.call(root, key)) { continue; } + var obj = root[key]; + + // If we are processing the `Ember` namespace, for example, the + // `paths` will start with `["Ember"]`. Every iteration through + // the loop will update the **second** element of this list with + // the key, so processing `Ember.View` will make the Array + // `['Ember', 'View']`. + paths[idx] = key; + + // If we have found an unprocessed class + if (obj && obj.toString === classToString) { + // Replace the class' `toString` with the dot-separated path + // and set its `NAME_KEY` + obj.toString = makeToString(paths.join('.')); + obj[NAME_KEY] = paths.join('.'); + + // Support nested namespaces + } else if (obj && obj.isNamespace) { + // Skip aliased namespaces + if (seen[guidFor(obj)]) { continue; } + seen[guidFor(obj)] = true; + + // Process the child namespace + processNamespace(paths, obj, seen); + } + } + + paths.length = idx; // cut out last item + } + + var STARTS_WITH_UPPERCASE = /^[A-Z]/; + + function tryIsNamespace(lookup, prop) { + try { + var obj = lookup[prop]; + return obj && obj.isNamespace && obj; + } catch (e) { + // continue + } + } + + function findNamespaces() { + var lookup = Ember.lookup; + var obj, isNamespace; + + if (Namespace.PROCESSED) { return; } + + for (var prop in lookup) { + // Only process entities that start with uppercase A-Z + if (!STARTS_WITH_UPPERCASE.test(prop)) { continue; } + + // Unfortunately, some versions of IE don't support window.hasOwnProperty + if (lookup.hasOwnProperty && !lookup.hasOwnProperty(prop)) { continue; } + + // At times we are not allowed to access certain properties for security reasons. + // There are also times where even if we can access them, we are not allowed to access their properties. + obj = tryIsNamespace(lookup, prop); + if (obj) { + obj[NAME_KEY] = prop; + } + } + } + + var NAME_KEY = Ember.NAME_KEY = GUID_KEY + '_name'; + + function superClassString(mixin) { + var superclass = mixin.superclass; + if (superclass) { + if (superclass[NAME_KEY]) { return superclass[NAME_KEY]; } + else { return superClassString(superclass); } + } else { + return; + } + } + + function classToString() { + if (!Ember.BOOTED && !this[NAME_KEY]) { + processAllNamespaces(); + } + + var ret; + + if (this[NAME_KEY]) { + ret = this[NAME_KEY]; + } else if (this._toString) { + ret = this._toString; + } else { + var str = superClassString(this); + if (str) { + ret = "(subclass of " + str + ")"; + } else { + ret = "(unknown mixin)"; + } + this.toString = makeToString(ret); + } + + return ret; + } + + function processAllNamespaces() { + var unprocessedNamespaces = !Namespace.PROCESSED; + var unprocessedMixins = Ember.anyUnprocessedMixins; + + if (unprocessedNamespaces) { + findNamespaces(); + Namespace.PROCESSED = true; + } + + if (unprocessedNamespaces || unprocessedMixins) { + var namespaces = Namespace.NAMESPACES; + var namespace; + + for (var i=0, l=namespaces.length; i 0) { + NativeArray = NativeArray.without.apply(NativeArray, ignore); + } + + /** + Creates an `Ember.NativeArray` from an Array like object. + Does not modify the original object. Ember.A is not needed if + `Ember.EXTEND_PROTOTYPES` is `true` (the default value). However, + it is recommended that you use Ember.A when creating addons for + ember or when you can not guarantee that `Ember.EXTEND_PROTOTYPES` + will be `true`. + + Example + + ```js + var Pagination = Ember.CollectionView.extend({ + tagName: 'ul', + classNames: ['pagination'], + + init: function() { + this._super(); + if (!this.get('content')) { + this.set('content', Ember.A()); + } + } + }); + ``` + + @method A + @for Ember + @return {Ember.NativeArray} + */ + var A = function(arr) { + if (arr === undefined) { arr = []; } + return EmberArray.detect(arr) ? arr : NativeArray.apply(arr); + }; + + /** + Activates the mixin on the Array.prototype if not already applied. Calling + this method more than once is safe. This will be called when ember is loaded + unless you have `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Array` + set to `false`. + + Example + + ```js + if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Array) { + Ember.NativeArray.activate(); + } + ``` + + @method activate + @for Ember.NativeArray + @static + @return {void} + */ + NativeArray.activate = function() { + NativeArray.apply(Array.prototype); + + A = function(arr) { return arr || []; }; + }; + + if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Array) { + NativeArray.activate(); + } + + Ember.A = A; // ES6TODO: Setting A onto the object returned by ember-metal/core to avoid circles + __exports__.A = A; + __exports__.NativeArray = NativeArray; + __exports__["default"] = NativeArray; + }); +enifed("ember-runtime/system/object", + ["ember-runtime/system/core_object","ember-runtime/mixins/observable","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var CoreObject = __dependency1__["default"]; + var Observable = __dependency2__["default"]; + + /** + `Ember.Object` is the main base class for all Ember objects. It is a subclass + of `Ember.CoreObject` with the `Ember.Observable` mixin applied. For details, + see the documentation for each of these. + + @class Object + @namespace Ember + @extends Ember.CoreObject + @uses Ember.Observable + */ + var EmberObject = CoreObject.extend(Observable); + EmberObject.toString = function() { + return "Ember.Object"; + }; + + __exports__["default"] = EmberObject; + }); +enifed("ember-runtime/system/object_proxy", + ["ember-runtime/system/object","ember-runtime/mixins/-proxy","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var EmberObject = __dependency1__["default"]; + var _ProxyMixin = __dependency2__["default"]; + + /** + `Ember.ObjectProxy` forwards all properties not defined by the proxy itself + to a proxied `content` object. + + ```javascript + object = Ember.Object.create({ + name: 'Foo' + }); + + proxy = Ember.ObjectProxy.create({ + content: object + }); + + // Access and change existing properties + proxy.get('name') // 'Foo' + proxy.set('name', 'Bar'); + object.get('name') // 'Bar' + + // Create new 'description' property on `object` + proxy.set('description', 'Foo is a whizboo baz'); + object.get('description') // 'Foo is a whizboo baz' + ``` + + While `content` is unset, setting a property to be delegated will throw an + Error. + + ```javascript + proxy = Ember.ObjectProxy.create({ + content: null, + flag: null + }); + proxy.set('flag', true); + proxy.get('flag'); // true + proxy.get('foo'); // undefined + proxy.set('foo', 'data'); // throws Error + ``` + + Delegated properties can be bound to and will change when content is updated. + + Computed properties on the proxy itself can depend on delegated properties. + + ```javascript + ProxyWithComputedProperty = Ember.ObjectProxy.extend({ + fullName: function () { + var firstName = this.get('firstName'), + lastName = this.get('lastName'); + if (firstName && lastName) { + return firstName + ' ' + lastName; + } + return firstName || lastName; + }.property('firstName', 'lastName') + }); + + proxy = ProxyWithComputedProperty.create(); + + proxy.get('fullName'); // undefined + proxy.set('content', { + firstName: 'Tom', lastName: 'Dale' + }); // triggers property change for fullName on proxy + + proxy.get('fullName'); // 'Tom Dale' + ``` + + @class ObjectProxy + @namespace Ember + @extends Ember.Object + @extends Ember._ProxyMixin + */ + + __exports__["default"] = EmberObject.extend(_ProxyMixin); + }); +enifed("ember-runtime/system/set", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/is_none","ember-runtime/system/string","ember-runtime/system/core_object","ember-runtime/mixins/mutable_enumerable","ember-runtime/mixins/enumerable","ember-runtime/mixins/copyable","ember-runtime/mixins/freezable","ember-metal/error","ember-metal/property_events","ember-metal/mixin","ember-metal/computed","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + var Ember = __dependency1__["default"]; + // Ember.isNone, Ember.A + + var get = __dependency2__.get; + var set = __dependency3__.set; + var guidFor = __dependency4__.guidFor; + var isNone = __dependency5__.isNone; + var fmt = __dependency6__.fmt; + var CoreObject = __dependency7__["default"]; + var MutableEnumerable = __dependency8__["default"]; + var Enumerable = __dependency9__["default"]; + var Copyable = __dependency10__["default"]; + var Freezable = __dependency11__.Freezable; + var FROZEN_ERROR = __dependency11__.FROZEN_ERROR; + var EmberError = __dependency12__["default"]; + var propertyWillChange = __dependency13__.propertyWillChange; + var propertyDidChange = __dependency13__.propertyDidChange; + var aliasMethod = __dependency14__.aliasMethod; + var computed = __dependency15__.computed; + + /** + An unordered collection of objects. + + A Set works a bit like an array except that its items are not ordered. You + can create a set to efficiently test for membership for an object. You can + also iterate through a set just like an array, even accessing objects by + index, however there is no guarantee as to their order. + + All Sets are observable via the Enumerable Observer API - which works + on any enumerable object including both Sets and Arrays. + + ## Creating a Set + + You can create a set like you would most objects using + `new Ember.Set()`. Most new sets you create will be empty, but you can + also initialize the set with some content by passing an array or other + enumerable of objects to the constructor. + + Finally, you can pass in an existing set and the set will be copied. You + can also create a copy of a set by calling `Ember.Set#copy()`. + + ```javascript + // creates a new empty set + var foundNames = new Ember.Set(); + + // creates a set with four names in it. + var names = new Ember.Set(["Charles", "Tom", "Juan", "Alex"]); // :P + + // creates a copy of the names set. + var namesCopy = new Ember.Set(names); + + // same as above. + var anotherNamesCopy = names.copy(); + ``` + + ## Adding/Removing Objects + + You generally add or remove objects from a set using `add()` or + `remove()`. You can add any type of object including primitives such as + numbers, strings, and booleans. + + Unlike arrays, objects can only exist one time in a set. If you call `add()` + on a set with the same object multiple times, the object will only be added + once. Likewise, calling `remove()` with the same object multiple times will + remove the object the first time and have no effect on future calls until + you add the object to the set again. + + NOTE: You cannot add/remove `null` or `undefined` to a set. Any attempt to do + so will be ignored. + + In addition to add/remove you can also call `push()`/`pop()`. Push behaves + just like `add()` but `pop()`, unlike `remove()` will pick an arbitrary + object, remove it and return it. This is a good way to use a set as a job + queue when you don't care which order the jobs are executed in. + + ## Testing for an Object + + To test for an object's presence in a set you simply call + `Ember.Set#contains()`. + + ## Observing changes + + When using `Ember.Set`, you can observe the `"[]"` property to be + alerted whenever the content changes. You can also add an enumerable + observer to the set to be notified of specific objects that are added and + removed from the set. See [Ember.Enumerable](/api/classes/Ember.Enumerable.html) + for more information on enumerables. + + This is often unhelpful. If you are filtering sets of objects, for instance, + it is very inefficient to re-filter all of the items each time the set + changes. It would be better if you could just adjust the filtered set based + on what was changed on the original set. The same issue applies to merging + sets, as well. + + ## Other Methods + + `Ember.Set` primary implements other mixin APIs. For a complete reference + on the methods you will use with `Ember.Set`, please consult these mixins. + The most useful ones will be `Ember.Enumerable` and + `Ember.MutableEnumerable` which implement most of the common iterator + methods you are used to on Array. + + Note that you can also use the `Ember.Copyable` and `Ember.Freezable` + APIs on `Ember.Set` as well. Once a set is frozen it can no longer be + modified. The benefit of this is that when you call `frozenCopy()` on it, + Ember will avoid making copies of the set. This allows you to write + code that can know with certainty when the underlying set data will or + will not be modified. + + @class Set + @namespace Ember + @extends Ember.CoreObject + @uses Ember.MutableEnumerable + @uses Ember.Copyable + @uses Ember.Freezable + @since Ember 0.9 + */ + __exports__["default"] = CoreObject.extend(MutableEnumerable, Copyable, Freezable, { + + // .......................................................... + // IMPLEMENT ENUMERABLE APIS + // + + /** + This property will change as the number of objects in the set changes. + + @property length + @type number + @default 0 + */ + length: 0, + + /** + Clears the set. This is useful if you want to reuse an existing set + without having to recreate it. + + ```javascript + var colors = new Ember.Set(["red", "green", "blue"]); + colors.length; // 3 + colors.clear(); + colors.length; // 0 + ``` + + @method clear + @return {Ember.Set} An empty Set + */ + clear: function() { + if (this.isFrozen) { throw new EmberError(FROZEN_ERROR); } + + var len = get(this, 'length'); + if (len === 0) { return this; } + + var guid; + + this.enumerableContentWillChange(len, 0); + propertyWillChange(this, 'firstObject'); + propertyWillChange(this, 'lastObject'); + + for (var i=0; i < len; i++) { + guid = guidFor(this[i]); + delete this[guid]; + delete this[i]; + } + + set(this, 'length', 0); + + propertyDidChange(this, 'firstObject'); + propertyDidChange(this, 'lastObject'); + this.enumerableContentDidChange(len, 0); + + return this; + }, + + /** + Returns true if the passed object is also an enumerable that contains the + same objects as the receiver. + + ```javascript + var colors = ["red", "green", "blue"], + same_colors = new Ember.Set(colors); + + same_colors.isEqual(colors); // true + same_colors.isEqual(["purple", "brown"]); // false + ``` + + @method isEqual + @param {Ember.Set} obj the other object. + @return {Boolean} + */ + isEqual: function(obj) { + // fail fast + if (!Enumerable.detect(obj)) return false; + + var loc = get(this, 'length'); + if (get(obj, 'length') !== loc) return false; + + while(--loc >= 0) { + if (!obj.contains(this[loc])) return false; + } + + return true; + }, + + /** + Adds an object to the set. Only non-`null` objects can be added to a set + and those can only be added once. If the object is already in the set or + the passed value is null this method will have no effect. + + This is an alias for `Ember.MutableEnumerable.addObject()`. + + ```javascript + var colors = new Ember.Set(); + colors.add("blue"); // ["blue"] + colors.add("blue"); // ["blue"] + colors.add("red"); // ["blue", "red"] + colors.add(null); // ["blue", "red"] + colors.add(undefined); // ["blue", "red"] + ``` + + @method add + @param {Object} obj The object to add. + @return {Ember.Set} The set itself. + */ + add: aliasMethod('addObject'), + + /** + Removes the object from the set if it is found. If you pass a `null` value + or an object that is already not in the set, this method will have no + effect. This is an alias for `Ember.MutableEnumerable.removeObject()`. + + ```javascript + var colors = new Ember.Set(["red", "green", "blue"]); + colors.remove("red"); // ["blue", "green"] + colors.remove("purple"); // ["blue", "green"] + colors.remove(null); // ["blue", "green"] + ``` + + @method remove + @param {Object} obj The object to remove + @return {Ember.Set} The set itself. + */ + remove: aliasMethod('removeObject'), + + /** + Removes the last element from the set and returns it, or `null` if it's empty. + + ```javascript + var colors = new Ember.Set(["green", "blue"]); + colors.pop(); // "blue" + colors.pop(); // "green" + colors.pop(); // null + ``` + + @method pop + @return {Object} The removed object from the set or null. + */ + pop: function() { + if (get(this, 'isFrozen')) throw new EmberError(FROZEN_ERROR); + var obj = this.length > 0 ? this[this.length-1] : null; + this.remove(obj); + return obj; + }, + + /** + Inserts the given object on to the end of the set. It returns + the set itself. + + This is an alias for `Ember.MutableEnumerable.addObject()`. + + ```javascript + var colors = new Ember.Set(); + colors.push("red"); // ["red"] + colors.push("green"); // ["red", "green"] + colors.push("blue"); // ["red", "green", "blue"] + ``` + + @method push + @return {Ember.Set} The set itself. + */ + push: aliasMethod('addObject'), + + /** + Removes the last element from the set and returns it, or `null` if it's empty. + + This is an alias for `Ember.Set.pop()`. + + ```javascript + var colors = new Ember.Set(["green", "blue"]); + colors.shift(); // "blue" + colors.shift(); // "green" + colors.shift(); // null + ``` + + @method shift + @return {Object} The removed object from the set or null. + */ + shift: aliasMethod('pop'), + + /** + Inserts the given object on to the end of the set. It returns + the set itself. + + This is an alias of `Ember.Set.push()` + + ```javascript + var colors = new Ember.Set(); + colors.unshift("red"); // ["red"] + colors.unshift("green"); // ["red", "green"] + colors.unshift("blue"); // ["red", "green", "blue"] + ``` + + @method unshift + @return {Ember.Set} The set itself. + */ + unshift: aliasMethod('push'), + + /** + Adds each object in the passed enumerable to the set. + + This is an alias of `Ember.MutableEnumerable.addObjects()` + + ```javascript + var colors = new Ember.Set(); + colors.addEach(["red", "green", "blue"]); // ["red", "green", "blue"] + ``` + + @method addEach + @param {Ember.Enumerable} objects the objects to add. + @return {Ember.Set} The set itself. + */ + addEach: aliasMethod('addObjects'), + + /** + Removes each object in the passed enumerable to the set. + + This is an alias of `Ember.MutableEnumerable.removeObjects()` + + ```javascript + var colors = new Ember.Set(["red", "green", "blue"]); + colors.removeEach(["red", "blue"]); // ["green"] + ``` + + @method removeEach + @param {Ember.Enumerable} objects the objects to remove. + @return {Ember.Set} The set itself. + */ + removeEach: aliasMethod('removeObjects'), + + // .......................................................... + // PRIVATE ENUMERABLE SUPPORT + // + + init: function(items) { + this._super(); + if (items) this.addObjects(items); + }, + + // implement Ember.Enumerable + nextObject: function(idx) { + return this[idx]; + }, + + // more optimized version + firstObject: computed(function() { + return this.length > 0 ? this[0] : undefined; + }), + + // more optimized version + lastObject: computed(function() { + return this.length > 0 ? this[this.length-1] : undefined; + }), + + // implements Ember.MutableEnumerable + addObject: function(obj) { + if (get(this, 'isFrozen')) throw new EmberError(FROZEN_ERROR); + if (isNone(obj)) return this; // nothing to do + + var guid = guidFor(obj); + var idx = this[guid]; + var len = get(this, 'length'); + var added; + + if (idx>=0 && idx=0 && idx=0; + }, + + copy: function() { + var C = this.constructor, ret = new C(), loc = get(this, 'length'); + set(ret, 'length', loc); + while(--loc>=0) { + ret[loc] = this[loc]; + ret[guidFor(this[loc])] = loc; + } + return ret; + }, + + toString: function() { + var len = this.length, idx, array = []; + for(idx = 0; idx < len; idx++) { + array[idx] = this[idx]; + } + return fmt("Ember.Set<%@>", [array.join(',')]); + } + }); + }); +enifed("ember-runtime/system/string", + ["ember-metal/core","ember-metal/utils","ember-metal/cache","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + var Ember = __dependency1__["default"]; + // Ember.STRINGS, Ember.FEATURES + var isArray = __dependency2__.isArray; + var emberInspect = __dependency2__.inspect; + + var Cache = __dependency3__["default"]; + + var STRING_DASHERIZE_REGEXP = (/[ _]/g); + + var STRING_DASHERIZE_CACHE = new Cache(1000, function(key) { + return decamelize(key).replace(STRING_DASHERIZE_REGEXP, '-'); + }); + + var CAMELIZE_CACHE = new Cache(1000, function(key) { + return key.replace(STRING_CAMELIZE_REGEXP, function(match, separator, chr) { + return chr ? chr.toUpperCase() : ''; + }).replace(/^([A-Z])/, function(match, separator, chr) { + return match.toLowerCase(); + }); + }); + + var CLASSIFY_CACHE = new Cache(1000, function(str) { + var parts = str.split("."); + var out = []; + + for (var i=0, l=parts.length; i 2) { + cachedFormats = new Array(arguments.length - 1); + + for (var i = 1, l = arguments.length; i < l; i++) { + cachedFormats[i - 1] = arguments[i]; + } + } + + // first, replace any ORDERED replacements. + var idx = 0; // the current index for non-numerical replacements + return str.replace(/%@([0-9]+)?/g, function(s, argIndex) { + argIndex = (argIndex) ? parseInt(argIndex, 10) - 1 : idx++; + s = cachedFormats[argIndex]; + return (s === null) ? '(null)' : (s === undefined) ? '' : emberInspect(s); + }); + } + + function loc(str, formats) { + if (!isArray(formats) || arguments.length > 2) { + formats = Array.prototype.slice.call(arguments, 1); + } + + str = Ember.STRINGS[str] || str; + return fmt(str, formats); + } + + function w(str) { + return str.split(/\s+/); + } + + function decamelize(str) { + return DECAMELIZE_CACHE.get(str); + } + + function dasherize(str) { + return STRING_DASHERIZE_CACHE.get(str); + } + + function camelize(str) { + return CAMELIZE_CACHE.get(str); + } + + function classify(str) { + return CLASSIFY_CACHE.get(str); + } + + function underscore(str) { + return UNDERSCORE_CACHE.get(str); + } + + function capitalize(str) { + return CAPITALIZE_CACHE.get(str); + } + + /** + Defines the hash of localized strings for the current language. Used by + the `Ember.String.loc()` helper. To localize, add string values to this + hash. + + @property STRINGS + @for Ember + @type Hash + */ + Ember.STRINGS = {}; + + /** + Defines string helper methods including string formatting and localization. + Unless `Ember.EXTEND_PROTOTYPES.String` is `false` these methods will also be + added to the `String.prototype` as well. + + @class String + @namespace Ember + @static + */ + __exports__["default"] = { + /** + Apply formatting options to the string. This will look for occurrences + of "%@" in your string and substitute them with the arguments you pass into + this method. If you want to control the specific order of replacement, + you can add a number after the key as well to indicate which argument + you want to insert. + + Ordered insertions are most useful when building loc strings where values + you need to insert may appear in different orders. + + ```javascript + "Hello %@ %@".fmt('John', 'Doe'); // "Hello John Doe" + "Hello %@2, %@1".fmt('John', 'Doe'); // "Hello Doe, John" + ``` + + @method fmt + @param {String} str The string to format + @param {Array} formats An array of parameters to interpolate into string. + @return {String} formatted string + */ + fmt: fmt, + + /** + Formats the passed string, but first looks up the string in the localized + strings hash. This is a convenient way to localize text. See + `Ember.String.fmt()` for more information on formatting. + + Note that it is traditional but not required to prefix localized string + keys with an underscore or other character so you can easily identify + localized strings. + + ```javascript + Ember.STRINGS = { + '_Hello World': 'Bonjour le monde', + '_Hello %@ %@': 'Bonjour %@ %@' + }; + + Ember.String.loc("_Hello World"); // 'Bonjour le monde'; + Ember.String.loc("_Hello %@ %@", ["John", "Smith"]); // "Bonjour John Smith"; + ``` + + @method loc + @param {String} str The string to format + @param {Array} formats Optional array of parameters to interpolate into string. + @return {String} formatted string + */ + loc: loc, + + /** + Splits a string into separate units separated by spaces, eliminating any + empty strings in the process. This is a convenience method for split that + is mostly useful when applied to the `String.prototype`. + + ```javascript + Ember.String.w("alpha beta gamma").forEach(function(key) { + console.log(key); + }); + + // > alpha + // > beta + // > gamma + ``` + + @method w + @param {String} str The string to split + @return {Array} array containing the split strings + */ + w: w, + + /** + Converts a camelized string into all lower case separated by underscores. + + ```javascript + 'innerHTML'.decamelize(); // 'inner_html' + 'action_name'.decamelize(); // 'action_name' + 'css-class-name'.decamelize(); // 'css-class-name' + 'my favorite items'.decamelize(); // 'my favorite items' + ``` + + @method decamelize + @param {String} str The string to decamelize. + @return {String} the decamelized string. + */ + decamelize: decamelize, + + /** + Replaces underscores, spaces, or camelCase with dashes. + + ```javascript + 'innerHTML'.dasherize(); // 'inner-html' + 'action_name'.dasherize(); // 'action-name' + 'css-class-name'.dasherize(); // 'css-class-name' + 'my favorite items'.dasherize(); // 'my-favorite-items' + ``` + + @method dasherize + @param {String} str The string to dasherize. + @return {String} the dasherized string. + */ + dasherize: dasherize, + + /** + Returns the lowerCamelCase form of a string. + + ```javascript + 'innerHTML'.camelize(); // 'innerHTML' + 'action_name'.camelize(); // 'actionName' + 'css-class-name'.camelize(); // 'cssClassName' + 'my favorite items'.camelize(); // 'myFavoriteItems' + 'My Favorite Items'.camelize(); // 'myFavoriteItems' + ``` + + @method camelize + @param {String} str The string to camelize. + @return {String} the camelized string. + */ + camelize: camelize, + + /** + Returns the UpperCamelCase form of a string. + + ```javascript + 'innerHTML'.classify(); // 'InnerHTML' + 'action_name'.classify(); // 'ActionName' + 'css-class-name'.classify(); // 'CssClassName' + 'my favorite items'.classify(); // 'MyFavoriteItems' + ``` + + @method classify + @param {String} str the string to classify + @return {String} the classified string + */ + classify: classify, + + /** + More general than decamelize. Returns the lower\_case\_and\_underscored + form of a string. + + ```javascript + 'innerHTML'.underscore(); // 'inner_html' + 'action_name'.underscore(); // 'action_name' + 'css-class-name'.underscore(); // 'css_class_name' + 'my favorite items'.underscore(); // 'my_favorite_items' + ``` + + @method underscore + @param {String} str The string to underscore. + @return {String} the underscored string. + */ + underscore: underscore, + + /** + Returns the Capitalized form of a string + + ```javascript + 'innerHTML'.capitalize() // 'InnerHTML' + 'action_name'.capitalize() // 'Action_name' + 'css-class-name'.capitalize() // 'Css-class-name' + 'my favorite items'.capitalize() // 'My favorite items' + ``` + + @method capitalize + @param {String} str The string to capitalize. + @return {String} The capitalized string. + */ + capitalize: capitalize + }; + + __exports__.fmt = fmt; + __exports__.loc = loc; + __exports__.w = w; + __exports__.decamelize = decamelize; + __exports__.dasherize = dasherize; + __exports__.camelize = camelize; + __exports__.classify = classify; + __exports__.underscore = underscore; + __exports__.capitalize = capitalize; + }); +enifed("ember-runtime/system/subarray", + ["ember-metal/property_get","ember-metal/error","ember-metal/enumerable_utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var EmberError = __dependency2__["default"]; + var EnumerableUtils = __dependency3__["default"]; + + var RETAIN = 'r'; + var FILTER = 'f'; + + function Operation(type, count) { + this.type = type; + this.count = count; + } + + __exports__["default"] = SubArray; + + /** + An `Ember.SubArray` tracks an array in a way similar to, but more specialized + than, `Ember.TrackedArray`. It is useful for keeping track of the indexes of + items within a filtered array. + + @class SubArray + @namespace Ember + */ + function SubArray (length) { + if (arguments.length < 1) { length = 0; } + + if (length > 0) { + this._operations = [new Operation(RETAIN, length)]; + } else { + this._operations = []; + } + } + + + SubArray.prototype = { + /** + Track that an item was added to the tracked array. + + @method addItem + + @param {Number} index The index of the item in the tracked array. + @param {Boolean} match `true` iff the item is included in the subarray. + + @return {number} The index of the item in the subarray. + */ + addItem: function(index, match) { + var returnValue = -1; + var itemType = match ? RETAIN : FILTER; + var self = this; + + this._findOperation(index, function(operation, operationIndex, rangeStart, rangeEnd, seenInSubArray) { + var newOperation, splitOperation; + + if (itemType === operation.type) { + ++operation.count; + } else if (index === rangeStart) { + // insert to the left of `operation` + self._operations.splice(operationIndex, 0, new Operation(itemType, 1)); + } else { + newOperation = new Operation(itemType, 1); + splitOperation = new Operation(operation.type, rangeEnd - index + 1); + operation.count = index - rangeStart; + + self._operations.splice(operationIndex + 1, 0, newOperation, splitOperation); + } + + if (match) { + if (operation.type === RETAIN) { + returnValue = seenInSubArray + (index - rangeStart); + } else { + returnValue = seenInSubArray; + } + } + + self._composeAt(operationIndex); + }, function(seenInSubArray) { + self._operations.push(new Operation(itemType, 1)); + + if (match) { + returnValue = seenInSubArray; + } + + self._composeAt(self._operations.length-1); + }); + + return returnValue; + }, + + /** + Track that an item was removed from the tracked array. + + @method removeItem + + @param {Number} index The index of the item in the tracked array. + + @return {number} The index of the item in the subarray, or `-1` if the item + was not in the subarray. + */ + removeItem: function(index) { + var returnValue = -1; + var self = this; + + this._findOperation(index, function (operation, operationIndex, rangeStart, rangeEnd, seenInSubArray) { + if (operation.type === RETAIN) { + returnValue = seenInSubArray + (index - rangeStart); + } + + if (operation.count > 1) { + --operation.count; + } else { + self._operations.splice(operationIndex, 1); + self._composeAt(operationIndex); + } + }, function() { + throw new EmberError("Can't remove an item that has never been added."); + }); + + return returnValue; + }, + + + _findOperation: function (index, foundCallback, notFoundCallback) { + var seenInSubArray = 0; + var operationIndex, len, operation, rangeStart, rangeEnd; + + // OPTIMIZE: change to balanced tree + // find leftmost operation to the right of `index` + for (operationIndex = rangeStart = 0, len = this._operations.length; operationIndex < len; rangeStart = rangeEnd + 1, ++operationIndex) { + operation = this._operations[operationIndex]; + rangeEnd = rangeStart + operation.count - 1; + + if (index >= rangeStart && index <= rangeEnd) { + foundCallback(operation, operationIndex, rangeStart, rangeEnd, seenInSubArray); + return; + } else if (operation.type === RETAIN) { + seenInSubArray += operation.count; + } + } + + notFoundCallback(seenInSubArray); + }, + + _composeAt: function(index) { + var op = this._operations[index]; + var otherOp; + + if (!op) { + // Composing out of bounds is a no-op, as when removing the last operation + // in the list. + return; + } + + if (index > 0) { + otherOp = this._operations[index-1]; + if (otherOp.type === op.type) { + op.count += otherOp.count; + this._operations.splice(index-1, 1); + --index; + } + } + + if (index < this._operations.length-1) { + otherOp = this._operations[index+1]; + if (otherOp.type === op.type) { + op.count += otherOp.count; + this._operations.splice(index+1, 1); + } + } + }, + + toString: function () { + var str = ""; + EnumerableUtils.forEach(this._operations, function (operation) { + str += " " + operation.type + ":" + operation.count; + }); + return str.substring(1); + } + }; + }); +enifed("ember-runtime/system/tracked_array", + ["ember-metal/property_get","ember-metal/enumerable_utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var forEach = __dependency2__.forEach; + + var RETAIN = 'r'; + var INSERT = 'i'; + var DELETE = 'd'; + + __exports__["default"] = TrackedArray; + + /** + An `Ember.TrackedArray` tracks array operations. It's useful when you want to + lazily compute the indexes of items in an array after they've been shifted by + subsequent operations. + + @class TrackedArray + @namespace Ember + @param {Array} [items=[]] The array to be tracked. This is used just to get + the initial items for the starting state of retain:n. + */ + function TrackedArray(items) { + if (arguments.length < 1) { items = []; } + + var length = get(items, 'length'); + + if (length) { + this._operations = [new ArrayOperation(RETAIN, length, items)]; + } else { + this._operations = []; + } + } + + TrackedArray.RETAIN = RETAIN; + TrackedArray.INSERT = INSERT; + TrackedArray.DELETE = DELETE; + + TrackedArray.prototype = { + + /** + Track that `newItems` were added to the tracked array at `index`. + + @method addItems + @param index + @param newItems + */ + addItems: function (index, newItems) { + var count = get(newItems, 'length'); + if (count < 1) { return; } + + var match = this._findArrayOperation(index); + var arrayOperation = match.operation; + var arrayOperationIndex = match.index; + var arrayOperationRangeStart = match.rangeStart; + var composeIndex, splitIndex, splitItems, splitArrayOperation, newArrayOperation; + + newArrayOperation = new ArrayOperation(INSERT, count, newItems); + + if (arrayOperation) { + if (!match.split) { + // insert left of arrayOperation + this._operations.splice(arrayOperationIndex, 0, newArrayOperation); + composeIndex = arrayOperationIndex; + } else { + this._split(arrayOperationIndex, index - arrayOperationRangeStart, newArrayOperation); + composeIndex = arrayOperationIndex + 1; + } + } else { + // insert at end + this._operations.push(newArrayOperation); + composeIndex = arrayOperationIndex; + } + + this._composeInsert(composeIndex); + }, + + /** + Track that `count` items were removed at `index`. + + @method removeItems + @param index + @param count + */ + removeItems: function (index, count) { + if (count < 1) { return; } + + var match = this._findArrayOperation(index); + var arrayOperation = match.operation; + var arrayOperationIndex = match.index; + var arrayOperationRangeStart = match.rangeStart; + var newArrayOperation, composeIndex; + + newArrayOperation = new ArrayOperation(DELETE, count); + if (!match.split) { + // insert left of arrayOperation + this._operations.splice(arrayOperationIndex, 0, newArrayOperation); + composeIndex = arrayOperationIndex; + } else { + this._split(arrayOperationIndex, index - arrayOperationRangeStart, newArrayOperation); + composeIndex = arrayOperationIndex + 1; + } + + return this._composeDelete(composeIndex); + }, + + /** + Apply all operations, reducing them to retain:n, for `n`, the number of + items in the array. + + `callback` will be called for each operation and will be passed the following arguments: + + * {array} items The items for the given operation + * {number} offset The computed offset of the items, ie the index in the + array of the first item for this operation. + * {string} operation The type of the operation. One of + `Ember.TrackedArray.{RETAIN, DELETE, INSERT}` + + @method apply + @param {Function} callback + */ + apply: function (callback) { + var items = []; + var offset = 0; + + forEach(this._operations, function (arrayOperation, operationIndex) { + callback(arrayOperation.items, offset, arrayOperation.type, operationIndex); + + if (arrayOperation.type !== DELETE) { + offset += arrayOperation.count; + items = items.concat(arrayOperation.items); + } + }); + + this._operations = [new ArrayOperation(RETAIN, items.length, items)]; + }, + + /** + Return an `ArrayOperationMatch` for the operation that contains the item at `index`. + + @method _findArrayOperation + + @param {Number} index the index of the item whose operation information + should be returned. + @private + */ + _findArrayOperation: function (index) { + var split = false; + var arrayOperationIndex, arrayOperation, + arrayOperationRangeStart, arrayOperationRangeEnd, + len; + + // OPTIMIZE: we could search these faster if we kept a balanced tree. + // find leftmost arrayOperation to the right of `index` + for (arrayOperationIndex = arrayOperationRangeStart = 0, len = this._operations.length; arrayOperationIndex < len; ++arrayOperationIndex) { + arrayOperation = this._operations[arrayOperationIndex]; + + if (arrayOperation.type === DELETE) { continue; } + + arrayOperationRangeEnd = arrayOperationRangeStart + arrayOperation.count - 1; + + if (index === arrayOperationRangeStart) { + break; + } else if (index > arrayOperationRangeStart && index <= arrayOperationRangeEnd) { + split = true; + break; + } else { + arrayOperationRangeStart = arrayOperationRangeEnd + 1; + } + } + + return new ArrayOperationMatch(arrayOperation, arrayOperationIndex, split, arrayOperationRangeStart); + }, + + _split: function (arrayOperationIndex, splitIndex, newArrayOperation) { + var arrayOperation = this._operations[arrayOperationIndex]; + var splitItems = arrayOperation.items.slice(splitIndex); + var splitArrayOperation = new ArrayOperation(arrayOperation.type, splitItems.length, splitItems); + + // truncate LHS + arrayOperation.count = splitIndex; + arrayOperation.items = arrayOperation.items.slice(0, splitIndex); + + this._operations.splice(arrayOperationIndex + 1, 0, newArrayOperation, splitArrayOperation); + }, + + // see SubArray for a better implementation. + _composeInsert: function (index) { + var newArrayOperation = this._operations[index]; + var leftArrayOperation = this._operations[index-1]; // may be undefined + var rightArrayOperation = this._operations[index+1]; // may be undefined + var leftOp = leftArrayOperation && leftArrayOperation.type; + var rightOp = rightArrayOperation && rightArrayOperation.type; + + if (leftOp === INSERT) { + // merge left + leftArrayOperation.count += newArrayOperation.count; + leftArrayOperation.items = leftArrayOperation.items.concat(newArrayOperation.items); + + if (rightOp === INSERT) { + // also merge right (we have split an insert with an insert) + leftArrayOperation.count += rightArrayOperation.count; + leftArrayOperation.items = leftArrayOperation.items.concat(rightArrayOperation.items); + this._operations.splice(index, 2); + } else { + // only merge left + this._operations.splice(index, 1); + } + } else if (rightOp === INSERT) { + // merge right + newArrayOperation.count += rightArrayOperation.count; + newArrayOperation.items = newArrayOperation.items.concat(rightArrayOperation.items); + this._operations.splice(index + 1, 1); + } + }, + + _composeDelete: function (index) { + var arrayOperation = this._operations[index]; + var deletesToGo = arrayOperation.count; + var leftArrayOperation = this._operations[index-1]; // may be undefined + var leftOp = leftArrayOperation && leftArrayOperation.type; + var nextArrayOperation; + var nextOp; + var nextCount; + var removeNewAndNextOp = false; + var removedItems = []; + + if (leftOp === DELETE) { + arrayOperation = leftArrayOperation; + index -= 1; + } + + for (var i = index + 1; deletesToGo > 0; ++i) { + nextArrayOperation = this._operations[i]; + nextOp = nextArrayOperation.type; + nextCount = nextArrayOperation.count; + + if (nextOp === DELETE) { + arrayOperation.count += nextCount; + continue; + } + + if (nextCount > deletesToGo) { + // d:2 {r,i}:5 we reduce the retain or insert, but it stays + removedItems = removedItems.concat(nextArrayOperation.items.splice(0, deletesToGo)); + nextArrayOperation.count -= deletesToGo; + + // In the case where we truncate the last arrayOperation, we don't need to + // remove it; also the deletesToGo reduction is not the entirety of + // nextCount + i -= 1; + nextCount = deletesToGo; + + deletesToGo = 0; + } else { + if (nextCount === deletesToGo) { + // Handle edge case of d:2 i:2 in which case both operations go away + // during composition. + removeNewAndNextOp = true; + } + removedItems = removedItems.concat(nextArrayOperation.items); + deletesToGo -= nextCount; + } + + if (nextOp === INSERT) { + // d:2 i:3 will result in delete going away + arrayOperation.count -= nextCount; + } + } + + if (arrayOperation.count > 0) { + // compose our new delete with possibly several operations to the right of + // disparate types + this._operations.splice(index+1, i-1-index); + } else { + // The delete operation can go away; it has merely reduced some other + // operation, as in d:3 i:4; it may also have eliminated that operation, + // as in d:3 i:3. + this._operations.splice(index, removeNewAndNextOp ? 2 : 1); + } + + return removedItems; + }, + + toString: function () { + var str = ""; + forEach(this._operations, function (operation) { + str += " " + operation.type + ":" + operation.count; + }); + return str.substring(1); + } + }; + + /** + Internal data structure to represent an array operation. + + @method ArrayOperation + @private + @param {String} type The type of the operation. One of + `Ember.TrackedArray.{RETAIN, INSERT, DELETE}` + @param {Number} count The number of items in this operation. + @param {Array} items The items of the operation, if included. RETAIN and + INSERT include their items, DELETE does not. + */ + function ArrayOperation (operation, count, items) { + this.type = operation; // RETAIN | INSERT | DELETE + this.count = count; + this.items = items; + } + + /** + Internal data structure used to include information when looking up operations + by item index. + + @method ArrayOperationMatch + @private + @param {ArrayOperation} operation + @param {Number} index The index of `operation` in the array of operations. + @param {Boolean} split Whether or not the item index searched for would + require a split for a new operation type. + @param {Number} rangeStart The index of the first item in the operation, + with respect to the tracked array. The index of the last item can be computed + from `rangeStart` and `operation.count`. + */ + function ArrayOperationMatch(operation, index, split, rangeStart) { + this.operation = operation; + this.index = index; + this.split = split; + this.rangeStart = rangeStart; + } + }); +enifed("ember-views", + ["ember-runtime","ember-views/system/jquery","ember-views/system/utils","ember-views/system/render_buffer","ember-views/system/ext","ember-views/views/states","ember-views/views/core_view","ember-views/views/view","ember-views/views/container_view","ember-views/views/collection_view","ember-views/views/component","ember-views/system/event_dispatcher","ember-views/mixins/view_target_action_support","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __exports__) { + "use strict"; + /** + Ember Views + + @module ember + @submodule ember-views + @requires ember-runtime + @main ember-views + */ + + // BEGIN IMPORTS + var Ember = __dependency1__["default"]; + var jQuery = __dependency2__["default"]; + var isSimpleClick = __dependency3__.isSimpleClick; + var RenderBuffer = __dependency4__["default"]; + // for the side effect of extending Ember.run.queues + var cloneStates = __dependency6__.cloneStates; + var states = __dependency6__.states; + + var CoreView = __dependency7__["default"]; + var View = __dependency8__["default"]; + var ContainerView = __dependency9__["default"]; + var CollectionView = __dependency10__["default"]; + var Component = __dependency11__["default"]; + + var EventDispatcher = __dependency12__["default"]; + var ViewTargetActionSupport = __dependency13__["default"]; + // END IMPORTS + + /** + Alias for jQuery + + @method $ + @for Ember + */ + + // BEGIN EXPORTS + Ember.$ = jQuery; + + Ember.ViewTargetActionSupport = ViewTargetActionSupport; + Ember.RenderBuffer = RenderBuffer; + + var ViewUtils = Ember.ViewUtils = {}; + ViewUtils.isSimpleClick = isSimpleClick; + + Ember.CoreView = CoreView; + Ember.View = View; + Ember.View.states = states; + Ember.View.cloneStates = cloneStates; + + Ember.ContainerView = ContainerView; + Ember.CollectionView = CollectionView; + Ember.Component = Component; + Ember.EventDispatcher = EventDispatcher; + // END EXPORTS + + __exports__["default"] = Ember; + }); +enifed("ember-views/mixins/component_template_deprecation", + ["ember-metal/core","ember-metal/property_get","ember-metal/mixin","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.deprecate + var get = __dependency2__.get; + var Mixin = __dependency3__.Mixin; + + /** + The ComponentTemplateDeprecation mixin is used to provide a useful + deprecation warning when using either `template` or `templateName` with + a component. The `template` and `templateName` properties specified at + extend time are moved to `layout` and `layoutName` respectively. + + `Ember.ComponentTemplateDeprecation` is used internally by Ember in + `Ember.Component`. + + @class ComponentTemplateDeprecation + @namespace Ember + */ + __exports__["default"] = Mixin.create({ + /** + @private + + Moves `templateName` to `layoutName` and `template` to `layout` at extend + time if a layout is not also specified. + + Note that this currently modifies the mixin themselves, which is technically + dubious but is practically of little consequence. This may change in the + future. + + @method willMergeMixin + @since 1.4.0 + */ + willMergeMixin: function(props) { + // must call _super here to ensure that the ActionHandler + // mixin is setup properly (moves actions -> _actions) + // + // Calling super is only OK here since we KNOW that + // there is another Mixin loaded first. + this._super.apply(this, arguments); + + var deprecatedProperty, replacementProperty; + var layoutSpecified = (props.layoutName || props.layout || get(this, 'layoutName')); + + if (props.templateName && !layoutSpecified) { + deprecatedProperty = 'templateName'; + replacementProperty = 'layoutName'; + + props.layoutName = props.templateName; + delete props['templateName']; + } + + if (props.template && !layoutSpecified) { + deprecatedProperty = 'template'; + replacementProperty = 'layout'; + + props.layout = props.template; + delete props['template']; + } + + if (deprecatedProperty) { + } + } + }); + }); +enifed("ember-views/mixins/view_target_action_support", + ["ember-metal/mixin","ember-runtime/mixins/target_action_support","ember-metal/computed","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Mixin = __dependency1__.Mixin; + var TargetActionSupport = __dependency2__["default"]; + + // ES6TODO: computed should have its own export path so you can do import {defaultTo} from computed + var computed = __dependency3__.computed; + var alias = computed.alias; + + /** + `Ember.ViewTargetActionSupport` is a mixin that can be included in a + view class to add a `triggerAction` method with semantics similar to + the Handlebars `{{action}}` helper. It provides intelligent defaults + for the action's target: the view's controller; and the context that is + sent with the action: the view's context. + + Note: In normal Ember usage, the `{{action}}` helper is usually the best + choice. This mixin is most often useful when you are doing more complex + event handling in custom View subclasses. + + For example: + + ```javascript + App.SaveButtonView = Ember.View.extend(Ember.ViewTargetActionSupport, { + action: 'save', + click: function() { + this.triggerAction(); // Sends the `save` action, along with the current context + // to the current controller + } + }); + ``` + + The `action` can be provided as properties of an optional object argument + to `triggerAction` as well. + + ```javascript + App.SaveButtonView = Ember.View.extend(Ember.ViewTargetActionSupport, { + click: function() { + this.triggerAction({ + action: 'save' + }); // Sends the `save` action, along with the current context + // to the current controller + } + }); + ``` + + @class ViewTargetActionSupport + @namespace Ember + @extends Ember.TargetActionSupport + */ + __exports__["default"] = Mixin.create(TargetActionSupport, { + /** + @property target + */ + target: alias('controller'), + /** + @property actionContext + */ + actionContext: alias('context') + }); + }); +enifed("ember-views/system/action_manager", + ["exports"], + function(__exports__) { + "use strict"; + /** + @module ember + @submodule ember-views + */ + + function ActionManager() {} + + /** + Global action id hash. + + @private + @property registeredActions + @type Object + */ + ActionManager.registeredActions = {}; + + __exports__["default"] = ActionManager; + }); +enifed("ember-views/system/event_dispatcher", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/is_none","ember-metal/run_loop","ember-metal/utils","ember-runtime/system/string","ember-runtime/system/object","ember-views/system/jquery","ember-views/system/action_manager","ember-views/views/view","ember-metal/merge","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-views + */ + var Ember = __dependency1__["default"]; + // Ember.assert + + var get = __dependency2__.get; + var set = __dependency3__.set; + var isNone = __dependency4__.isNone; + var run = __dependency5__["default"]; + var typeOf = __dependency6__.typeOf; + var fmt = __dependency7__.fmt; + var EmberObject = __dependency8__["default"]; + var jQuery = __dependency9__["default"]; + var ActionManager = __dependency10__["default"]; + var View = __dependency11__["default"]; + var merge = __dependency12__["default"]; + + //ES6TODO: + // find a better way to do Ember.View.views without global state + + /** + `Ember.EventDispatcher` handles delegating browser events to their + corresponding `Ember.Views.` For example, when you click on a view, + `Ember.EventDispatcher` ensures that that view's `mouseDown` method gets + called. + + @class EventDispatcher + @namespace Ember + @private + @extends Ember.Object + */ + __exports__["default"] = EmberObject.extend({ + + /** + The set of events names (and associated handler function names) to be setup + and dispatched by the `EventDispatcher`. Custom events can added to this list at setup + time, generally via the `Ember.Application.customEvents` hash. Only override this + default set to prevent the EventDispatcher from listening on some events all together. + + This set will be modified by `setup` to also include any events added at that time. + + @property events + @type Object + */ + events: { + touchstart : 'touchStart', + touchmove : 'touchMove', + touchend : 'touchEnd', + touchcancel : 'touchCancel', + keydown : 'keyDown', + keyup : 'keyUp', + keypress : 'keyPress', + mousedown : 'mouseDown', + mouseup : 'mouseUp', + contextmenu : 'contextMenu', + click : 'click', + dblclick : 'doubleClick', + mousemove : 'mouseMove', + focusin : 'focusIn', + focusout : 'focusOut', + mouseenter : 'mouseEnter', + mouseleave : 'mouseLeave', + submit : 'submit', + input : 'input', + change : 'change', + dragstart : 'dragStart', + drag : 'drag', + dragenter : 'dragEnter', + dragleave : 'dragLeave', + dragover : 'dragOver', + drop : 'drop', + dragend : 'dragEnd' + }, + + /** + The root DOM element to which event listeners should be attached. Event + listeners will be attached to the document unless this is overridden. + + Can be specified as a DOMElement or a selector string. + + The default body is a string since this may be evaluated before document.body + exists in the DOM. + + @private + @property rootElement + @type DOMElement + @default 'body' + */ + rootElement: 'body', + + /** + It enables events to be dispatched to the view's `eventManager.` When present, + this object takes precedence over handling of events on the view itself. + + Note that most Ember applications do not use this feature. If your app also + does not use it, consider setting this property to false to gain some performance + improvement by allowing the EventDispatcher to skip the search for the + `eventManager` on the view tree. + + ```javascript + var EventDispatcher = Em.EventDispatcher.extend({ + events: { + click : 'click', + focusin : 'focusIn', + focusout : 'focusOut', + change : 'change' + }, + canDispatchToEventManager: false + }); + container.register('event_dispatcher:main', EventDispatcher); + ``` + + @property canDispatchToEventManager + @type boolean + @default 'true' + @since 1.7.0 + */ + canDispatchToEventManager: true, + + /** + Sets up event listeners for standard browser events. + + This will be called after the browser sends a `DOMContentReady` event. By + default, it will set up all of the listeners on the document body. If you + would like to register the listeners on a different element, set the event + dispatcher's `root` property. + + @private + @method setup + @param addedEvents {Hash} + */ + setup: function(addedEvents, rootElement) { + var event, events = get(this, 'events'); + + merge(events, addedEvents || {}); + + if (!isNone(rootElement)) { + set(this, 'rootElement', rootElement); + } + + rootElement = jQuery(get(this, 'rootElement')); + + + rootElement.addClass('ember-application'); + + + for (event in events) { + if (events.hasOwnProperty(event)) { + this.setupHandler(rootElement, event, events[event]); + } + } + }, + + /** + Registers an event listener on the rootElement. If the given event is + triggered, the provided event handler will be triggered on the target view. + + If the target view does not implement the event handler, or if the handler + returns `false`, the parent view will be called. The event will continue to + bubble to each successive parent view until it reaches the top. + + @private + @method setupHandler + @param {Element} rootElement + @param {String} event the browser-originated event to listen to + @param {String} eventName the name of the method to call on the view + */ + setupHandler: function(rootElement, event, eventName) { + var self = this; + + rootElement.on(event + '.ember', '.ember-view', function(evt, triggeringManager) { + var view = View.views[this.id]; + var result = true; + + var manager = self.canDispatchToEventManager ? self._findNearestEventManager(view, eventName) : null; + + if (manager && manager !== triggeringManager) { + result = self._dispatchEvent(manager, evt, eventName, view); + } else if (view) { + result = self._bubbleEvent(view, evt, eventName); + } + + return result; + }); + + rootElement.on(event + '.ember', '[data-ember-action]', function(evt) { + var actionId = jQuery(evt.currentTarget).attr('data-ember-action'); + var action = ActionManager.registeredActions[actionId]; + + // We have to check for action here since in some cases, jQuery will trigger + // an event on `removeChild` (i.e. focusout) after we've already torn down the + // action handlers for the view. + if (action && action.eventName === eventName) { + return action.handler(evt); + } + }); + }, + + _findNearestEventManager: function(view, eventName) { + var manager = null; + + while (view) { + manager = get(view, 'eventManager'); + if (manager && manager[eventName]) { break; } + + view = get(view, 'parentView'); + } + + return manager; + }, + + _dispatchEvent: function(object, evt, eventName, view) { + var result = true; + + var handler = object[eventName]; + if (typeOf(handler) === 'function') { + result = run(object, handler, evt, view); + // Do not preventDefault in eventManagers. + evt.stopPropagation(); + } + else { + result = this._bubbleEvent(view, evt, eventName); + } + + return result; + }, + + _bubbleEvent: function(view, evt, eventName) { + return run(view, view.handleEvent, eventName, evt); + }, + + destroy: function() { + var rootElement = get(this, 'rootElement'); + jQuery(rootElement).off('.ember', '**').removeClass('ember-application'); + return this._super(); + }, + + toString: function() { + return '(EventDispatcher)'; + } + }); + }); +enifed("ember-views/system/ext", + ["ember-metal/run_loop"], + function(__dependency1__) { + "use strict"; + /** + @module ember + @submodule ember-views + */ + + var run = __dependency1__["default"]; + + // Add a new named queue for rendering views that happens + // after bindings have synced, and a queue for scheduling actions + // that that should occur after view rendering. + var queues = run.queues; + run._addQueue('render', 'actions'); + run._addQueue('afterRender', 'render'); + }); +enifed("ember-views/system/jquery", + ["ember-metal/core","ember-runtime/system/string","ember-metal/enumerable_utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert + var w = __dependency2__.w; + + // ES6TODO: the functions on EnumerableUtils need their own exports + var forEach = __dependency3__.forEach; + + /** + Ember Views + + @module ember + @submodule ember-views + @requires ember-runtime + @main ember-views + */ + + var jQuery = (Ember.imports && Ember.imports.jQuery) || (this && this.jQuery); + if (!jQuery && typeof eriuqer === 'function') { + jQuery = eriuqer('jquery'); + } + + + /** + @module ember + @submodule ember-views + */ + if (jQuery) { + // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#dndevents + var dragEvents = w('dragstart drag dragenter dragleave dragover drop dragend'); + + // Copies the `dataTransfer` property from a browser event object onto the + // jQuery event object for the specified events + forEach(dragEvents, function(eventName) { + jQuery.event.fixHooks[eventName] = { props: ['dataTransfer'] }; + }); + } + + __exports__["default"] = jQuery; + }); +enifed("ember-views/system/render_buffer", + ["ember-views/system/jquery","morph","ember-metal/core","ember-metal/platform","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-views + */ + + var jQuery = __dependency1__["default"]; + var DOMHelper = __dependency2__.DOMHelper; + var Ember = __dependency3__["default"]; + var create = __dependency4__.create; + + // The HTML spec allows for "omitted start tags". These tags are optional + // when their intended child is the first thing in the parent tag. For + // example, this is a tbody start tag: + // + // + // + // + // + // The tbody may be omitted, and the browser will accept and render: + // + //
    + // + // + // However, the omitted start tag will still be added to the DOM. Here + // we test the string and context to see if the browser is about to + // perform this cleanup, but with a special allowance for disregarding + // + ``` + + And associate it by name using a view's `templateName` property: + + ```javascript + AView = Ember.View.extend({ + templateName: 'some-template' + }); + ``` + + If you have nested resources, your Handlebars template will look like this: + + ```html + + ``` + + And `templateName` property: + + ```javascript + AView = Ember.View.extend({ + templateName: 'posts/new' + }); + ``` + + Using a value for `templateName` that does not have a Handlebars template + with a matching `data-template-name` attribute will throw an error. + + For views classes that may have a template later defined (e.g. as the block + portion of a `{{view}}` Handlebars helper call in another template or in + a subclass), you can provide a `defaultTemplate` property set to compiled + template function. If a template is not later provided for the view instance + the `defaultTemplate` value will be used: + + ```javascript + AView = Ember.View.extend({ + defaultTemplate: Ember.Handlebars.compile('I was the default'), + template: null, + templateName: null + }); + ``` + + Will result in instances with an HTML representation of: + + ```html +
    I was the default
    + ``` + + If a `template` or `templateName` is provided it will take precedence over + `defaultTemplate`: + + ```javascript + AView = Ember.View.extend({ + defaultTemplate: Ember.Handlebars.compile('I was the default') + }); + + aView = AView.create({ + template: Ember.Handlebars.compile('I was the template, not default') + }); + ``` + + Will result in the following HTML representation when rendered: + + ```html +
    I was the template, not default
    + ``` + + ## View Context + + The default context of the compiled template is the view's controller: + + ```javascript + AView = Ember.View.extend({ + template: Ember.Handlebars.compile('Hello {{excitedGreeting}}') + }); + + aController = Ember.Object.create({ + firstName: 'Barry', + excitedGreeting: function() { + return this.get("content.firstName") + "!!!" + }.property() + }); + + aView = AView.create({ + controller: aController + }); + ``` + + Will result in an HTML representation of: + + ```html +
    Hello Barry!!!
    + ``` + + A context can also be explicitly supplied through the view's `context` + property. If the view has neither `context` nor `controller` properties, the + `parentView`'s context will be used. + + ## Layouts + + Views can have a secondary template that wraps their main template. Like + primary templates, layouts can be any function that accepts an optional + context parameter and returns a string of HTML that will be inserted inside + view's tag. Views whose HTML element is self closing (e.g. ``) + cannot have a layout and this property will be ignored. + + Most typically in Ember a layout will be a compiled `Ember.Handlebars` + template. + + A view's layout can be set directly with the `layout` property or reference + an existing Handlebars template by name with the `layoutName` property. + + A template used as a layout must contain a single use of the Handlebars + `{{yield}}` helper. The HTML contents of a view's rendered `template` will be + inserted at this location: + + ```javascript + AViewWithLayout = Ember.View.extend({ + layout: Ember.Handlebars.compile("
    {{yield}}
    "), + template: Ember.Handlebars.compile("I got wrapped") + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html +
    +
    + I got wrapped +
    +
    + ``` + + See [Ember.Handlebars.helpers.yield](/api/classes/Ember.Handlebars.helpers.html#method_yield) + for more information. + + ## Responding to Browser Events + + Views can respond to user-initiated events in one of three ways: method + implementation, through an event manager, and through `{{action}}` helper use + in their template or layout. + + ### Method Implementation + + Views can respond to user-initiated events by implementing a method that + matches the event name. A `jQuery.Event` object will be passed as the + argument to this method. + + ```javascript + AView = Ember.View.extend({ + click: function(event) { + // will be called when when an instance's + // rendered element is clicked + } + }); + ``` + + ### Event Managers + + Views can define an object as their `eventManager` property. This object can + then implement methods that match the desired event names. Matching events + that occur on the view's rendered HTML or the rendered HTML of any of its DOM + descendants will trigger this method. A `jQuery.Event` object will be passed + as the first argument to the method and an `Ember.View` object as the + second. The `Ember.View` will be the view whose rendered HTML was interacted + with. This may be the view with the `eventManager` property or one of its + descendent views. + + ```javascript + AView = Ember.View.extend({ + eventManager: Ember.Object.create({ + doubleClick: function(event, view) { + // will be called when when an instance's + // rendered element or any rendering + // of this views's descendent + // elements is clicked + } + }) + }); + ``` + + An event defined for an event manager takes precedence over events of the + same name handled through methods on the view. + + ```javascript + AView = Ember.View.extend({ + mouseEnter: function(event) { + // will never trigger. + }, + eventManager: Ember.Object.create({ + mouseEnter: function(event, view) { + // takes precedence over AView#mouseEnter + } + }) + }); + ``` + + Similarly a view's event manager will take precedence for events of any views + rendered as a descendent. A method name that matches an event name will not + be called if the view instance was rendered inside the HTML representation of + a view that has an `eventManager` property defined that handles events of the + name. Events not handled by the event manager will still trigger method calls + on the descendent. + + ```javascript + var App = Ember.Application.create(); + App.OuterView = Ember.View.extend({ + template: Ember.Handlebars.compile("outer {{#view 'inner'}}inner{{/view}} outer"), + eventManager: Ember.Object.create({ + mouseEnter: function(event, view) { + // view might be instance of either + // OuterView or InnerView depending on + // where on the page the user interaction occured + } + }) + }); + + App.InnerView = Ember.View.extend({ + click: function(event) { + // will be called if rendered inside + // an OuterView because OuterView's + // eventManager doesn't handle click events + }, + mouseEnter: function(event) { + // will never be called if rendered inside + // an OuterView. + } + }); + ``` + + ### Handlebars `{{action}}` Helper + + See [Handlebars.helpers.action](/api/classes/Ember.Handlebars.helpers.html#method_action). + + ### Event Names + + All of the event handling approaches described above respond to the same set + of events. The names of the built-in events are listed below. (The hash of + built-in events exists in `Ember.EventDispatcher`.) Additional, custom events + can be registered by using `Ember.Application.customEvents`. + + Touch events: + + * `touchStart` + * `touchMove` + * `touchEnd` + * `touchCancel` + + Keyboard events + + * `keyDown` + * `keyUp` + * `keyPress` + + Mouse events + + * `mouseDown` + * `mouseUp` + * `contextMenu` + * `click` + * `doubleClick` + * `mouseMove` + * `focusIn` + * `focusOut` + * `mouseEnter` + * `mouseLeave` + + Form events: + + * `submit` + * `change` + * `focusIn` + * `focusOut` + * `input` + + HTML5 drag and drop events: + + * `dragStart` + * `drag` + * `dragEnter` + * `dragLeave` + * `dragOver` + * `dragEnd` + * `drop` + + ## Handlebars `{{view}}` Helper + + Other `Ember.View` instances can be included as part of a view's template by + using the `{{view}}` Handlebars helper. See [Ember.Handlebars.helpers.view](/api/classes/Ember.Handlebars.helpers.html#method_view) + for additional information. + + @class View + @namespace Ember + @extends Ember.CoreView + */ + var View = CoreView.extend({ + + concatenatedProperties: ['classNames', 'classNameBindings', 'attributeBindings'], + + /** + @property isView + @type Boolean + @default true + @static + */ + isView: true, + + // .......................................................... + // TEMPLATE SUPPORT + // + + /** + The name of the template to lookup if no template is provided. + + By default `Ember.View` will lookup a template with this name in + `Ember.TEMPLATES` (a shared global object). + + @property templateName + @type String + @default null + */ + templateName: null, + + /** + The name of the layout to lookup if no layout is provided. + + By default `Ember.View` will lookup a template with this name in + `Ember.TEMPLATES` (a shared global object). + + @property layoutName + @type String + @default null + */ + layoutName: null, + + /** + Used to identify this view during debugging + + @property instrumentDisplay + @type String + */ + instrumentDisplay: computed(function() { + if (this.helperName) { + return '{{' + this.helperName + '}}'; + } + }), + + /** + The template used to render the view. This should be a function that + accepts an optional context parameter and returns a string of HTML that + will be inserted into the DOM relative to its parent view. + + In general, you should set the `templateName` property instead of setting + the template yourself. + + @property template + @type Function + */ + template: computed('templateName', function(key, value) { + if (value !== undefined) { return value; } + + var templateName = get(this, 'templateName'); + var template = this.templateForName(templateName, 'template'); + + + return template || get(this, 'defaultTemplate'); + }), + + /** + The controller managing this view. If this property is set, it will be + made available for use by the template. + + @property controller + @type Object + */ + controller: computed('_parentView', function(key) { + var parentView = get(this, '_parentView'); + return parentView ? get(parentView, 'controller') : null; + }), + + /** + A view may contain a layout. A layout is a regular template but + supersedes the `template` property during rendering. It is the + responsibility of the layout template to retrieve the `template` + property from the view (or alternatively, call `Handlebars.helpers.yield`, + `{{yield}}`) to render it in the correct location. + + This is useful for a view that has a shared wrapper, but which delegates + the rendering of the contents of the wrapper to the `template` property + on a subclass. + + @property layout + @type Function + */ + layout: computed(function(key) { + var layoutName = get(this, 'layoutName'); + var layout = this.templateForName(layoutName, 'layout'); + + + return layout || get(this, 'defaultLayout'); + }).property('layoutName'), + + _yield: function(context, options) { + var template = get(this, 'template'); + if (template) { template(context, options); } + }, + + templateForName: function(name, type) { + if (!name) { return; } + + if (!this.container) { + throw new EmberError('Container was not found when looking up a views template. ' + + 'This is most likely due to manually instantiating an Ember.View. ' + + 'See: http://git.io/EKPpnA'); + } + + return this.container.lookup('template:' + name); + }, + + /** + The object from which templates should access properties. + + This object will be passed to the template function each time the render + method is called, but it is up to the individual function to decide what + to do with it. + + By default, this will be the view's controller. + + @property context + @type Object + */ + context: computed(function(key, value) { + if (arguments.length === 2) { + set(this, '_context', value); + return value; + } else { + return get(this, '_context'); + } + })["volatile"](), + + /** + Private copy of the view's template context. This can be set directly + by Handlebars without triggering the observer that causes the view + to be re-rendered. + + The context of a view is looked up as follows: + + 1. Supplied context (usually by Handlebars) + 2. Specified controller + 3. `parentView`'s context (for a child of a ContainerView) + + The code in Handlebars that overrides the `_context` property first + checks to see whether the view has a specified controller. This is + something of a hack and should be revisited. + + @property _context + @private + */ + _context: computed(function(key) { + var parentView, controller; + + if (controller = get(this, 'controller')) { + return controller; + } + + parentView = this._parentView; + if (parentView) { + return get(parentView, '_context'); + } + + return null; + }), + + /** + If a value that affects template rendering changes, the view should be + re-rendered to reflect the new value. + + @method _contextDidChange + @private + */ + _contextDidChange: observer('context', function() { + this.rerender(); + }), + + /** + If `false`, the view will appear hidden in DOM. + + @property isVisible + @type Boolean + @default null + */ + isVisible: true, + + /** + Array of child views. You should never edit this array directly. + Instead, use `appendChild` and `removeFromParent`. + + @property childViews + @type Array + @default [] + @private + */ + childViews: childViewsProperty, + + _childViews: EMPTY_ARRAY, + + // When it's a virtual view, we need to notify the parent that their + // childViews will change. + _childViewsWillChange: beforeObserver('childViews', function() { + if (this.isVirtual) { + var parentView = get(this, 'parentView'); + if (parentView) { propertyWillChange(parentView, 'childViews'); } + } + }), + + // When it's a virtual view, we need to notify the parent that their + // childViews did change. + _childViewsDidChange: observer('childViews', function() { + if (this.isVirtual) { + var parentView = get(this, 'parentView'); + if (parentView) { propertyDidChange(parentView, 'childViews'); } + } + }), + + /** + Return the nearest ancestor that is an instance of the provided + class. + + @method nearestInstanceOf + @param {Class} klass Subclass of Ember.View (or Ember.View itself) + @return Ember.View + @deprecated + */ + nearestInstanceOf: function(klass) { + var view = get(this, 'parentView'); + + while (view) { + if (view instanceof klass) { return view; } + view = get(view, 'parentView'); + } + }, + + /** + Return the nearest ancestor that is an instance of the provided + class or mixin. + + @method nearestOfType + @param {Class,Mixin} klass Subclass of Ember.View (or Ember.View itself), + or an instance of Ember.Mixin. + @return Ember.View + */ + nearestOfType: function(klass) { + var view = get(this, 'parentView'); + var isOfType = klass instanceof Mixin ? + function(view) { return klass.detect(view); } : + function(view) { return klass.detect(view.constructor); }; + + while (view) { + if (isOfType(view)) { return view; } + view = get(view, 'parentView'); + } + }, + + /** + Return the nearest ancestor that has a given property. + + @method nearestWithProperty + @param {String} property A property name + @return Ember.View + */ + nearestWithProperty: function(property) { + var view = get(this, 'parentView'); + + while (view) { + if (property in view) { return view; } + view = get(view, 'parentView'); + } + }, + + /** + Return the nearest ancestor whose parent is an instance of + `klass`. + + @method nearestChildOf + @param {Class} klass Subclass of Ember.View (or Ember.View itself) + @return Ember.View + */ + nearestChildOf: function(klass) { + var view = get(this, 'parentView'); + + while (view) { + if (get(view, 'parentView') instanceof klass) { return view; } + view = get(view, 'parentView'); + } + }, + + /** + When the parent view changes, recursively invalidate `controller` + + @method _parentViewDidChange + @private + */ + _parentViewDidChange: observer('_parentView', function() { + if (this.isDestroying) { return; } + + this.trigger('parentViewDidChange'); + + if (get(this, 'parentView.controller') && !get(this, 'controller')) { + this.notifyPropertyChange('controller'); + } + }), + + _controllerDidChange: observer('controller', function() { + if (this.isDestroying) { return; } + + this.rerender(); + + this.forEachChildView(function(view) { + view.propertyDidChange('controller'); + }); + }), + + cloneKeywords: function() { + var templateData = get(this, 'templateData'); + + var keywords = templateData ? copy(templateData.keywords) : {}; + set(keywords, 'view', this.isVirtual ? keywords.view : this); + set(keywords, '_view', this); + set(keywords, 'controller', get(this, 'controller')); + + return keywords; + }, + + /** + Called on your view when it should push strings of HTML into a + `Ember.RenderBuffer`. Most users will want to override the `template` + or `templateName` properties instead of this method. + + By default, `Ember.View` will look for a function in the `template` + property and invoke it with the value of `context`. The value of + `context` will be the view's controller unless you override it. + + @method render + @param {Ember.RenderBuffer} buffer The render buffer + */ + render: function(buffer) { + // If this view has a layout, it is the responsibility of the + // the layout to render the view's template. Otherwise, render the template + // directly. + var template = get(this, 'layout') || get(this, 'template'); + + if (template) { + var context = get(this, 'context'); + var keywords = this.cloneKeywords(); + var output; + + var data = { + view: this, + buffer: buffer, + isRenderData: true, + keywords: keywords, + insideGroup: get(this, 'templateData.insideGroup') + }; + + // Invoke the template with the provided template context, which + // is the view's controller by default. A hash of data is also passed that provides + // the template with access to the view and render buffer. + + // The template should write directly to the render buffer instead + // of returning a string. + output = template(context, { data: data }); + + // If the template returned a string instead of writing to the buffer, + // push the string onto the buffer. + if (output !== undefined) { buffer.push(output); } + } + }, + + /** + Renders the view again. This will work regardless of whether the + view is already in the DOM or not. If the view is in the DOM, the + rendering process will be deferred to give bindings a chance + to synchronize. + + If children were added during the rendering process using `appendChild`, + `rerender` will remove them, because they will be added again + if needed by the next `render`. + + In general, if the display of your view changes, you should modify + the DOM element directly instead of manually calling `rerender`, which can + be slow. + + @method rerender + */ + rerender: function() { + return this.currentState.rerender(this); + }, + + /** + Iterates over the view's `classNameBindings` array, inserts the value + of the specified property into the `classNames` array, then creates an + observer to update the view's element if the bound property ever changes + in the future. + + @method _applyClassNameBindings + @private + */ + _applyClassNameBindings: function(classBindings) { + var classNames = this.classNames; + var elem, newClass, dasherizedClass; + + // Loop through all of the configured bindings. These will be either + // property names ('isUrgent') or property paths relative to the view + // ('content.isUrgent') + forEach(classBindings, function(binding) { + + + // Variable in which the old class value is saved. The observer function + // closes over this variable, so it knows which string to remove when + // the property changes. + var oldClass; + // Extract just the property name from bindings like 'foo:bar' + var parsedPath = View._parsePropertyPath(binding); + + // Set up an observer on the context. If the property changes, toggle the + // class name. + var observer = function() { + // Get the current value of the property + newClass = this._classStringForProperty(binding); + elem = this.$(); + + // If we had previously added a class to the element, remove it. + if (oldClass) { + elem.removeClass(oldClass); + // Also remove from classNames so that if the view gets rerendered, + // the class doesn't get added back to the DOM. + classNames.removeObject(oldClass); + } + + // If necessary, add a new class. Make sure we keep track of it so + // it can be removed in the future. + if (newClass) { + elem.addClass(newClass); + oldClass = newClass; + } else { + oldClass = null; + } + }; + + // Get the class name for the property at its current value + dasherizedClass = this._classStringForProperty(binding); + + if (dasherizedClass) { + // Ensure that it gets into the classNames array + // so it is displayed when we render. + addObject(classNames, dasherizedClass); + + // Save a reference to the class name so we can remove it + // if the observer fires. Remember that this variable has + // been closed over by the observer. + oldClass = dasherizedClass; + } + + this.registerObserver(this, parsedPath.path, observer); + // Remove className so when the view is rerendered, + // the className is added based on binding reevaluation + this.one('willClearRender', function() { + if (oldClass) { + classNames.removeObject(oldClass); + oldClass = null; + } + }); + + }, this); + }, + + _unspecifiedAttributeBindings: null, + + /** + Iterates through the view's attribute bindings, sets up observers for each, + then applies the current value of the attributes to the passed render buffer. + + @method _applyAttributeBindings + @param {Ember.RenderBuffer} buffer + @private + */ + _applyAttributeBindings: function(buffer, attributeBindings) { + var attributeValue; + var unspecifiedAttributeBindings = this._unspecifiedAttributeBindings = this._unspecifiedAttributeBindings || {}; + + forEach(attributeBindings, function(binding) { + var split = binding.split(':'); + var property = split[0]; + var attributeName = split[1] || property; + + if (property in this) { + this._setupAttributeBindingObservation(property, attributeName); + + // Determine the current value and add it to the render buffer + // if necessary. + attributeValue = get(this, property); + View.applyAttributeBindings(buffer, attributeName, attributeValue); + } else { + unspecifiedAttributeBindings[property] = attributeName; + } + }, this); + + // Lazily setup setUnknownProperty after attributeBindings are initially applied + this.setUnknownProperty = this._setUnknownProperty; + }, + + _setupAttributeBindingObservation: function(property, attributeName) { + var attributeValue, elem; + + // Create an observer to add/remove/change the attribute if the + // JavaScript property changes. + var observer = function() { + elem = this.$(); + + attributeValue = get(this, property); + + View.applyAttributeBindings(elem, attributeName, attributeValue); + }; + + this.registerObserver(this, property, observer); + }, + + /** + We're using setUnknownProperty as a hook to setup attributeBinding observers for + properties that aren't defined on a view at initialization time. + + Note: setUnknownProperty will only be called once for each property. + + @method setUnknownProperty + @param key + @param value + @private + */ + setUnknownProperty: null, // Gets defined after initialization by _applyAttributeBindings + + _setUnknownProperty: function(key, value) { + var attributeName = this._unspecifiedAttributeBindings && this._unspecifiedAttributeBindings[key]; + if (attributeName) { + this._setupAttributeBindingObservation(key, attributeName); + } + + defineProperty(this, key); + return set(this, key, value); + }, + + /** + Given a property name, returns a dasherized version of that + property name if the property evaluates to a non-falsy value. + + For example, if the view has property `isUrgent` that evaluates to true, + passing `isUrgent` to this method will return `"is-urgent"`. + + @method _classStringForProperty + @param property + @private + */ + _classStringForProperty: function(property) { + var parsedPath = View._parsePropertyPath(property); + var path = parsedPath.path; + + var val = get(this, path); + if (val === undefined && isGlobalPath(path)) { + val = get(Ember.lookup, path); + } + + return View._classStringForValue(path, val, parsedPath.className, parsedPath.falsyClassName); + }, + + // .......................................................... + // ELEMENT SUPPORT + // + + /** + Returns the current DOM element for the view. + + @property element + @type DOMElement + */ + element: null, + + /** + Returns a jQuery object for this view's element. If you pass in a selector + string, this method will return a jQuery object, using the current element + as its buffer. + + For example, calling `view.$('li')` will return a jQuery object containing + all of the `li` elements inside the DOM element of this view. + + @method $ + @param {String} [selector] a jQuery-compatible selector string + @return {jQuery} the jQuery object for the DOM node + */ + $: function(sel) { + return this.currentState.$(this, sel); + }, + + mutateChildViews: function(callback) { + var childViews = this._childViews; + var idx = childViews.length; + var view; + + while(--idx >= 0) { + view = childViews[idx]; + callback(this, view, idx); + } + + return this; + }, + + forEachChildView: function(callback) { + var childViews = this._childViews; + + if (!childViews) { return this; } + + var len = childViews.length; + var view, idx; + + for (idx = 0; idx < len; idx++) { + view = childViews[idx]; + callback(view); + } + + return this; + }, + + /** + Appends the view's element to the specified parent element. + + If the view does not have an HTML representation yet, `createElement()` + will be called automatically. + + Note that this method just schedules the view to be appended; the DOM + element will not be appended to the given element until all bindings have + finished synchronizing. + + This is not typically a function that you will need to call directly when + building your application. You might consider using `Ember.ContainerView` + instead. If you do need to use `appendTo`, be sure that the target element + you are providing is associated with an `Ember.Application` and does not + have an ancestor element that is associated with an Ember view. + + @method appendTo + @param {String|DOMElement|jQuery} A selector, element, HTML string, or jQuery object + @return {Ember.View} receiver + */ + appendTo: function(selector) { + var target = jQuery(selector); + + + this.constructor.renderer.appendTo(this, target[0]); + + return this; + }, + + /** + Replaces the content of the specified parent element with this view's + element. If the view does not have an HTML representation yet, + `createElement()` will be called automatically. + + Note that this method just schedules the view to be appended; the DOM + element will not be appended to the given element until all bindings have + finished synchronizing + + @method replaceIn + @param {String|DOMElement|jQuery} target A selector, element, HTML string, or jQuery object + @return {Ember.View} received + */ + replaceIn: function(selector) { + var target = jQuery(selector); + + + this.constructor.renderer.replaceIn(this, target[0]); + + return this; + }, + + /** + Appends the view's element to the document body. If the view does + not have an HTML representation yet, `createElement()` will be called + automatically. + + If your application uses the `rootElement` property, you must append + the view within that element. Rendering views outside of the `rootElement` + is not supported. + + Note that this method just schedules the view to be appended; the DOM + element will not be appended to the document body until all bindings have + finished synchronizing. + + @method append + @return {Ember.View} receiver + */ + append: function() { + return this.appendTo(document.body); + }, + + /** + Removes the view's element from the element to which it is attached. + + @method remove + @return {Ember.View} receiver + */ + remove: function() { + // What we should really do here is wait until the end of the run loop + // to determine if the element has been re-appended to a different + // element. + // In the interim, we will just re-render if that happens. It is more + // important than elements get garbage collected. + if (!this.removedFromDOM) { this.destroyElement(); } + }, + + elementId: null, + + /** + Attempts to discover the element in the parent element. The default + implementation looks for an element with an ID of `elementId` (or the + view's guid if `elementId` is null). You can override this method to + provide your own form of lookup. For example, if you want to discover your + element using a CSS class name instead of an ID. + + @method findElementInParentElement + @param {DOMElement} parentElement The parent's DOM element + @return {DOMElement} The discovered element + */ + findElementInParentElement: function(parentElem) { + var id = "#" + this.elementId; + return jQuery(id)[0] || jQuery(id, parentElem)[0]; + }, + + /** + Creates a DOM representation of the view and all of its child views by + recursively calling the `render()` method. + + After the element has been inserted into the DOM, `didInsertElement` will + be called on this view and all of its child views. + + @method createElement + @return {Ember.View} receiver + */ + createElement: function() { + if (this.element) { return this; } + + this._didCreateElementWithoutMorph = true; + this.constructor.renderer.renderTree(this); + + return this; + }, + + /** + Called when a view is going to insert an element into the DOM. + + @event willInsertElement + */ + willInsertElement: Ember.K, + + /** + Called when the element of the view has been inserted into the DOM + or after the view was re-rendered. Override this function to do any + set up that requires an element in the document body. + + When a view has children, didInsertElement will be called on the + child view(s) first, bubbling upwards through the hierarchy. + + @event didInsertElement + */ + didInsertElement: Ember.K, + + /** + Called when the view is about to rerender, but before anything has + been torn down. This is a good opportunity to tear down any manual + observers you have installed based on the DOM state + + @event willClearRender + */ + willClearRender: Ember.K, + + /** + Destroys any existing element along with the element for any child views + as well. If the view does not currently have a element, then this method + will do nothing. + + If you implement `willDestroyElement()` on your view, then this method will + be invoked on your view before your element is destroyed to give you a + chance to clean up any event handlers, etc. + + If you write a `willDestroyElement()` handler, you can assume that your + `didInsertElement()` handler was called earlier for the same element. + + You should not call or override this method yourself, but you may + want to implement the above callbacks. + + @method destroyElement + @return {Ember.View} receiver + */ + destroyElement: function() { + return this.currentState.destroyElement(this); + }, + + /** + Called when the element of the view is going to be destroyed. Override + this function to do any teardown that requires an element, like removing + event listeners. + + Please note: any property changes made during this event will have no + effect on object observers. + + @event willDestroyElement + */ + willDestroyElement: Ember.K, + + /** + Called when the parentView property has changed. + + @event parentViewDidChange + */ + parentViewDidChange: Ember.K, + + instrumentName: 'view', + + instrumentDetails: function(hash) { + hash.template = get(this, 'templateName'); + this._super(hash); + }, + + beforeRender: function(buffer) {}, + + afterRender: function(buffer) {}, + + applyAttributesToBuffer: function(buffer) { + // Creates observers for all registered class name and attribute bindings, + // then adds them to the element. + var classNameBindings = get(this, 'classNameBindings'); + if (classNameBindings.length) { + this._applyClassNameBindings(classNameBindings); + } + + // Pass the render buffer so the method can apply attributes directly. + // This isn't needed for class name bindings because they use the + // existing classNames infrastructure. + var attributeBindings = get(this, 'attributeBindings'); + if (attributeBindings.length) { + this._applyAttributeBindings(buffer, attributeBindings); + } + + buffer.setClasses(this.classNames); + buffer.id(this.elementId); + + var role = get(this, 'ariaRole'); + if (role) { + buffer.attr('role', role); + } + + if (get(this, 'isVisible') === false) { + buffer.style('display', 'none'); + } + }, + + // .......................................................... + // STANDARD RENDER PROPERTIES + // + + /** + Tag name for the view's outer element. The tag name is only used when an + element is first created. If you change the `tagName` for an element, you + must destroy and recreate the view element. + + By default, the render buffer will use a `
    ` tag for views. + + @property tagName + @type String + @default null + */ + + // We leave this null by default so we can tell the difference between + // the default case and a user-specified tag. + tagName: null, + + /** + The WAI-ARIA role of the control represented by this view. For example, a + button may have a role of type 'button', or a pane may have a role of + type 'alertdialog'. This property is used by assistive software to help + visually challenged users navigate rich web applications. + + The full list of valid WAI-ARIA roles is available at: + [http://www.w3.org/TR/wai-aria/roles#roles_categorization](http://www.w3.org/TR/wai-aria/roles#roles_categorization) + + @property ariaRole + @type String + @default null + */ + ariaRole: null, + + /** + Standard CSS class names to apply to the view's outer element. This + property automatically inherits any class names defined by the view's + superclasses as well. + + @property classNames + @type Array + @default ['ember-view'] + */ + classNames: ['ember-view'], + + /** + A list of properties of the view to apply as class names. If the property + is a string value, the value of that string will be applied as a class + name. + + ```javascript + // Applies the 'high' class to the view element + Ember.View.extend({ + classNameBindings: ['priority'] + priority: 'high' + }); + ``` + + If the value of the property is a Boolean, the name of that property is + added as a dasherized class name. + + ```javascript + // Applies the 'is-urgent' class to the view element + Ember.View.extend({ + classNameBindings: ['isUrgent'] + isUrgent: true + }); + ``` + + If you would prefer to use a custom value instead of the dasherized + property name, you can pass a binding like this: + + ```javascript + // Applies the 'urgent' class to the view element + Ember.View.extend({ + classNameBindings: ['isUrgent:urgent'] + isUrgent: true + }); + ``` + + This list of properties is inherited from the view's superclasses as well. + + @property classNameBindings + @type Array + @default [] + */ + classNameBindings: EMPTY_ARRAY, + + /** + A list of properties of the view to apply as attributes. If the property is + a string value, the value of that string will be applied as the attribute. + + ```javascript + // Applies the type attribute to the element + // with the value "button", like
    + Ember.View.extend({ + attributeBindings: ['type'], + type: 'button' + }); + ``` + + If the value of the property is a Boolean, the name of that property is + added as an attribute. + + ```javascript + // Renders something like
    + Ember.View.extend({ + attributeBindings: ['enabled'], + enabled: true + }); + ``` + + @property attributeBindings + */ + attributeBindings: EMPTY_ARRAY, + + // ....................................................... + // CORE DISPLAY METHODS + // + + /** + Setup a view, but do not finish waking it up. + + * configure `childViews` + * register the view with the global views hash, which is used for event + dispatch + + @method init + @private + */ + init: function() { + if (!this.isVirtual && !this.elementId) { + this.elementId = guidFor(this); + } + + this._super(); + + // setup child views. be sure to clone the child views array first + this._childViews = this._childViews.slice(); + + this.classNameBindings = emberA(this.classNameBindings.slice()); + + this.classNames = emberA(this.classNames.slice()); + }, + + appendChild: function(view, options) { + return this.currentState.appendChild(this, view, options); + }, + + /** + Removes the child view from the parent view. + + @method removeChild + @param {Ember.View} view + @return {Ember.View} receiver + */ + removeChild: function(view) { + // If we're destroying, the entire subtree will be + // freed, and the DOM will be handled separately, + // so no need to mess with childViews. + if (this.isDestroying) { return; } + + // update parent node + set(view, '_parentView', null); + + // remove view from childViews array. + var childViews = this._childViews; + + removeObject(childViews, view); + + this.propertyDidChange('childViews'); // HUH?! what happened to will change? + + return this; + }, + + /** + Removes all children from the `parentView`. + + @method removeAllChildren + @return {Ember.View} receiver + */ + removeAllChildren: function() { + return this.mutateChildViews(function(parentView, view) { + parentView.removeChild(view); + }); + }, + + destroyAllChildren: function() { + return this.mutateChildViews(function(parentView, view) { + view.destroy(); + }); + }, + + /** + Removes the view from its `parentView`, if one is found. Otherwise + does nothing. + + @method removeFromParent + @return {Ember.View} receiver + */ + removeFromParent: function() { + var parent = this._parentView; + + // Remove DOM element from parent + this.remove(); + + if (parent) { parent.removeChild(this); } + return this; + }, + + /** + You must call `destroy` on a view to destroy the view (and all of its + child views). This will remove the view from any parent node, then make + sure that the DOM element managed by the view can be released by the + memory manager. + + @method destroy + */ + destroy: function() { + var childViews = this._childViews; + // get parentView before calling super because it'll be destroyed + var nonVirtualParentView = get(this, 'parentView'); + var viewName = this.viewName; + var childLen, i; + + if (!this._super()) { return; } + + // remove from non-virtual parent view if viewName was specified + if (viewName && nonVirtualParentView) { + nonVirtualParentView.set(viewName, null); + } + + return this; + }, + + /** + Instantiates a view to be added to the childViews array during view + initialization. You generally will not call this method directly unless + you are overriding `createChildViews()`. Note that this method will + automatically configure the correct settings on the new view instance to + act as a child of the parent. + + @method createChildView + @param {Class|String} viewClass + @param {Hash} [attrs] Attributes to add + @return {Ember.View} new instance + */ + createChildView: function(view, attrs) { + if (!view) { + throw new TypeError("createChildViews first argument must exist"); + } + + if (view.isView && view._parentView === this && view.container === this.container) { + return view; + } + + attrs = attrs || {}; + attrs._parentView = this; + + if (CoreView.detect(view)) { + attrs.templateData = attrs.templateData || get(this, 'templateData'); + + attrs.container = this.container; + view = view.create(attrs); + + // don't set the property on a virtual view, as they are invisible to + // consumers of the view API + if (view.viewName) { + set(get(this, 'concreteView'), view.viewName, view); + } + } else if ('string' === typeof view) { + var fullName = 'view:' + view; + var ViewKlass = this.container.lookupFactory(fullName); + + + attrs.templateData = get(this, 'templateData'); + view = ViewKlass.create(attrs); + } else { + attrs.container = this.container; + + if (!get(view, 'templateData')) { + attrs.templateData = get(this, 'templateData'); + } + + setProperties(view, attrs); + + } + + return view; + }, + + becameVisible: Ember.K, + becameHidden: Ember.K, + + /** + When the view's `isVisible` property changes, toggle the visibility + element of the actual DOM element. + + @method _isVisibleDidChange + @private + */ + _isVisibleDidChange: observer('isVisible', function() { + if (this._isVisible === get(this, 'isVisible')) { return ; } + run.scheduleOnce('render', this, this._toggleVisibility); + }), + + _toggleVisibility: function() { + var $el = this.$(); + var isVisible = get(this, 'isVisible'); + + if (this._isVisible === isVisible) { return ; } + + // It's important to keep these in sync, even if we don't yet have + // an element in the DOM to manipulate: + this._isVisible = isVisible; + + if (!$el) { return; } + + $el.toggle(isVisible); + + if (this._isAncestorHidden()) { return; } + + if (isVisible) { + this._notifyBecameVisible(); + } else { + this._notifyBecameHidden(); + } + }, + + _notifyBecameVisible: function() { + this.trigger('becameVisible'); + + this.forEachChildView(function(view) { + var isVisible = get(view, 'isVisible'); + + if (isVisible || isVisible === null) { + view._notifyBecameVisible(); + } + }); + }, + + _notifyBecameHidden: function() { + this.trigger('becameHidden'); + this.forEachChildView(function(view) { + var isVisible = get(view, 'isVisible'); + + if (isVisible || isVisible === null) { + view._notifyBecameHidden(); + } + }); + }, + + _isAncestorHidden: function() { + var parent = get(this, 'parentView'); + + while (parent) { + if (get(parent, 'isVisible') === false) { return true; } + + parent = get(parent, 'parentView'); + } + + return false; + }, + transitionTo: function(state, children) { + this._transitionTo(state, children); + }, + _transitionTo: function(state, children) { + var priorState = this.currentState; + var currentState = this.currentState = this._states[state]; + this._state = state; + + if (priorState && priorState.exit) { priorState.exit(this); } + if (currentState.enter) { currentState.enter(this); } + }, + + // ....................................................... + // EVENT HANDLING + // + + /** + Handle events from `Ember.EventDispatcher` + + @method handleEvent + @param eventName {String} + @param evt {Event} + @private + */ + handleEvent: function(eventName, evt) { + return this.currentState.handleEvent(this, eventName, evt); + }, + + registerObserver: function(root, path, target, observer) { + if (!observer && 'function' === typeof target) { + observer = target; + target = null; + } + + if (!root || typeof root !== 'object') { + return; + } + + var view = this; + var stateCheckedObserver = function() { + view.currentState.invokeObserver(this, observer); + }; + var scheduledObserver = function() { + run.scheduleOnce('render', this, stateCheckedObserver); + }; + + addObserver(root, path, target, scheduledObserver); + + this.one('willClearRender', function() { + removeObserver(root, path, target, scheduledObserver); + }); + } + + }); + deprecateProperty(View.prototype, 'state', '_state'); + deprecateProperty(View.prototype, 'states', '_states'); + + /* + Describe how the specified actions should behave in the various + states that a view can exist in. Possible states: + + * preRender: when a view is first instantiated, and after its + element was destroyed, it is in the preRender state + * inBuffer: once a view has been rendered, but before it has + been inserted into the DOM, it is in the inBuffer state + * hasElement: the DOM representation of the view is created, + and is ready to be inserted + * inDOM: once a view has been inserted into the DOM it is in + the inDOM state. A view spends the vast majority of its + existence in this state. + * destroyed: once a view has been destroyed (using the destroy + method), it is in this state. No further actions can be invoked + on a destroyed view. + */ + + // in the destroyed state, everything is illegal + + // before rendering has begun, all legal manipulations are noops. + + // inside the buffer, legal manipulations are done on the buffer + + // once the view has been inserted into the DOM, legal manipulations + // are done on the DOM element. + + function notifyMutationListeners() { + run.once(View, 'notifyMutationListeners'); + } + + View.reopenClass({ + + /** + Parse a path and return an object which holds the parsed properties. + + For example a path like "content.isEnabled:enabled:disabled" will return the + following object: + + ```javascript + { + path: "content.isEnabled", + className: "enabled", + falsyClassName: "disabled", + classNames: ":enabled:disabled" + } + ``` + + @method _parsePropertyPath + @static + @private + */ + _parsePropertyPath: function(path) { + var split = path.split(':'); + var propertyPath = split[0]; + var classNames = ""; + var className, falsyClassName; + + // check if the property is defined as prop:class or prop:trueClass:falseClass + if (split.length > 1) { + className = split[1]; + if (split.length === 3) { falsyClassName = split[2]; } + + classNames = ':' + className; + if (falsyClassName) { classNames += ":" + falsyClassName; } + } + + return { + path: propertyPath, + classNames: classNames, + className: (className === '') ? undefined : className, + falsyClassName: falsyClassName + }; + }, + + /** + Get the class name for a given value, based on the path, optional + `className` and optional `falsyClassName`. + + - if a `className` or `falsyClassName` has been specified: + - if the value is truthy and `className` has been specified, + `className` is returned + - if the value is falsy and `falsyClassName` has been specified, + `falsyClassName` is returned + - otherwise `null` is returned + - if the value is `true`, the dasherized last part of the supplied path + is returned + - if the value is not `false`, `undefined` or `null`, the `value` + is returned + - if none of the above rules apply, `null` is returned + + @method _classStringForValue + @param path + @param val + @param className + @param falsyClassName + @static + @private + */ + _classStringForValue: function(path, val, className, falsyClassName) { + if(isArray(val)) { + val = get(val, 'length') !== 0; + } + + // When using the colon syntax, evaluate the truthiness or falsiness + // of the value to determine which className to return + if (className || falsyClassName) { + if (className && !!val) { + return className; + + } else if (falsyClassName && !val) { + return falsyClassName; + + } else { + return null; + } + + // If value is a Boolean and true, return the dasherized property + // name. + } else if (val === true) { + // Normalize property path to be suitable for use + // as a class name. For exaple, content.foo.barBaz + // becomes bar-baz. + var parts = path.split('.'); + return dasherize(parts[parts.length-1]); + + // If the value is not false, undefined, or null, return the current + // value of the property. + } else if (val !== false && val != null) { + return val; + + // Nothing to display. Return null so that the old class is removed + // but no new class is added. + } else { + return null; + } + } + }); + + var mutation = EmberObject.extend(Evented).create(); + // TODO MOVE TO RENDERER HOOKS + View.addMutationListener = function(callback) { + mutation.on('change', callback); + }; + + View.removeMutationListener = function(callback) { + mutation.off('change', callback); + }; + + View.notifyMutationListeners = function() { + mutation.trigger('change'); + }; + + /** + Global views hash + + @property views + @static + @type Hash + */ + View.views = {}; + + // If someone overrides the child views computed property when + // defining their class, we want to be able to process the user's + // supplied childViews and then restore the original computed property + // at view initialization time. This happens in Ember.ContainerView's init + // method. + View.childViewsProperty = childViewsProperty; + + View.applyAttributeBindings = function(elem, name, value) { + var type = typeOf(value); + + // if this changes, also change the logic in ember-handlebars/lib/helpers/binding.js + if (name !== 'value' && (type === 'string' || (type === 'number' && !isNaN(value)))) { + if (value !== elem.attr(name)) { + elem.attr(name, value); + } + } else if (name === 'value' || type === 'boolean') { + if (isNone(value) || value === false) { + // `null`, `undefined` or `false` should remove attribute + elem.removeAttr(name); + // In IE8 `prop` couldn't remove attribute when name is `required`. + if (name === 'required') { + elem.removeProp(name); + } else { + elem.prop(name, ''); + } + } else if (value !== elem.prop(name)) { + // value should always be properties + elem.prop(name, value); + } + } else if (!value) { + elem.removeAttr(name); + } + }; + + __exports__["default"] = View; + }); +enifed("ember", + ["ember-metal","ember-runtime","ember-handlebars","ember-views","ember-routing","ember-routing-handlebars","ember-application","ember-extension-support"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__) { + "use strict"; + /* global navigator */ + // require the main entry points for each of these packages + // this is so that the global exports occur properly + + // do this to ensure that Ember.Test is defined properly on the global + // if it is present. + if (Ember.__loader.registry['ember-testing']) { + requireModule('ember-testing'); + } + + /** + Ember + + @module ember + */ + + }); +enifed("morph", + ["./morph/morph","./morph/dom-helper","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Morph = __dependency1__["default"]; + var Morph; + __exports__.Morph = Morph; + var DOMHelper = __dependency2__["default"]; + var DOMHelper; + __exports__.DOMHelper = DOMHelper; + }); +enifed("morph/dom-helper", + ["../morph/morph","./dom-helper/build-html-dom","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Morph = __dependency1__["default"]; + var buildHTMLDOM = __dependency2__.buildHTMLDOM; + var svgNamespace = __dependency2__.svgNamespace; + var svgHTMLIntegrationPoints = __dependency2__.svgHTMLIntegrationPoints; + + var deletesBlankTextNodes = (function(){ + var element = document.createElement('div'); + element.appendChild( document.createTextNode('') ); + var clonedElement = element.cloneNode(true); + return clonedElement.childNodes.length === 0; + })(); + + var ignoresCheckedAttribute = (function(){ + var element = document.createElement('input'); + element.setAttribute('checked', 'checked'); + var clonedElement = element.cloneNode(false); + return !clonedElement.checked; + })(); + + function isSVG(ns){ + return ns === svgNamespace; + } + + // This is not the namespace of the element, but of + // the elements inside that elements. + function interiorNamespace(element){ + if ( + element && + element.namespaceURI === svgNamespace && + !svgHTMLIntegrationPoints[element.tagName] + ) { + return svgNamespace; + } else { + return null; + } + } + + // The HTML spec allows for "omitted start tags". These tags are optional + // when their intended child is the first thing in the parent tag. For + // example, this is a tbody start tag: + // + //
    + // + // + // + // The tbody may be omitted, and the browser will accept and render: + // + //
    + // + // + // However, the omitted start tag will still be added to the DOM. Here + // we test the string and context to see if the browser is about to + // perform this cleanup. + // + // http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#optional-tags + // describes which tags are omittable. The spec for tbody and colgroup + // explains this behavior: + // + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-tbody-element + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-colgroup-element + // + + var omittedStartTagChildTest = /<([\w:]+)/; + function detectOmittedStartTag(string, contextualElement){ + // Omitted start tags are only inside table tags. + if (contextualElement.tagName === 'TABLE') { + var omittedStartTagChildMatch = omittedStartTagChildTest.exec(string); + if (omittedStartTagChildMatch) { + var omittedStartTagChild = omittedStartTagChildMatch[1]; + // It is already asserted that the contextual element is a table + // and not the proper start tag. Just see if a tag was omitted. + return omittedStartTagChild === 'tr' || + omittedStartTagChild === 'col'; + } + } + } + + function buildSVGDOM(html, dom){ + var div = dom.document.createElement('div'); + div.innerHTML = ''+html+''; + return div.firstChild.childNodes; + } + + /* + * A class wrapping DOM functions to address environment compatibility, + * namespaces, contextual elements for morph un-escaped content + * insertion. + * + * When entering a template, a DOMHelper should be passed: + * + * template(context, { hooks: hooks, dom: new DOMHelper() }); + * + * TODO: support foreignObject as a passed contextual element. It has + * a namespace (svg) that does not match its internal namespace + * (xhtml). + * + * @class DOMHelper + * @constructor + * @param {HTMLDocument} _document The document DOM methods are proxied to + */ + function DOMHelper(_document){ + this.document = _document || window.document; + this.namespace = null; + } + + var prototype = DOMHelper.prototype; + prototype.constructor = DOMHelper; + + prototype.insertBefore = function(element, childElement, referenceChild) { + return element.insertBefore(childElement, referenceChild); + }; + + prototype.appendChild = function(element, childElement) { + return element.appendChild(childElement); + }; + + prototype.appendText = function(element, text) { + return element.appendChild(this.document.createTextNode(text)); + }; + + prototype.setAttribute = function(element, name, value) { + element.setAttribute(name, value); + }; + + if (document.createElementNS) { + // Only opt into namespace detection if a contextualElement + // is passed. + prototype.createElement = function(tagName, contextualElement) { + var namespace = this.namespace; + if (contextualElement) { + if (tagName === 'svg') { + namespace = svgNamespace; + } else { + namespace = interiorNamespace(contextualElement); + } + } + if (namespace) { + return this.document.createElementNS(namespace, tagName); + } else { + return this.document.createElement(tagName); + } + }; + } else { + prototype.createElement = function(tagName) { + return this.document.createElement(tagName); + }; + } + + prototype.setNamespace = function(ns) { + this.namespace = ns; + }; + + prototype.detectNamespace = function(element) { + this.namespace = interiorNamespace(element); + }; + + prototype.createDocumentFragment = function(){ + return this.document.createDocumentFragment(); + }; + + prototype.createTextNode = function(text){ + return this.document.createTextNode(text); + }; + + prototype.repairClonedNode = function(element, blankChildTextNodes, isChecked){ + if (deletesBlankTextNodes && blankChildTextNodes.length > 0) { + for (var i=0, len=blankChildTextNodes.length;i]*)>", 'i'))[0]; + var endTag = ''; + + var wrappedHTML = [startTag, html, endTag]; + + var i = wrappingTags.length; + var wrappedDepth = 1 + i; + while(i--) { + wrappedHTML.unshift('<'+wrappingTags[i]+'>'); + wrappedHTML.push(''); + } + + var wrapper = document.createElement('div'); + scriptSafeInnerHTML(wrapper, wrappedHTML.join('')); + var element = wrapper; + while (wrappedDepth--) { + element = element.firstChild; + while (element && element.nodeType !== 1) { + element = element.nextSibling; + } + } + while (element && element.tagName !== tagName) { + element = element.nextSibling; + } + return element ? element.childNodes : []; + } + + var buildDOM; + if (needsShy) { + buildDOM = function buildDOM(html, contextualElement, dom){ + contextualElement = dom.cloneNode(contextualElement, false); + scriptSafeInnerHTML(contextualElement, html); + return contextualElement.childNodes; + }; + } else { + buildDOM = function buildDOM(html, contextualElement, dom){ + contextualElement = dom.cloneNode(contextualElement, false); + contextualElement.innerHTML = html; + return contextualElement.childNodes; + }; + } + + + var buildIESafeDOM; + if (tagNamesRequiringInnerHTMLFix || movesWhitespace) { + buildIESafeDOM = function buildIESafeDOM(html, contextualElement, dom) { + // Make a list of the leading text on script nodes. Include + // script tags without any whitespace for easier processing later. + var spacesBefore = []; + var spacesAfter = []; + html = html.replace(/(\s*)()(\s*)/g, function(match, tag, spaces) { + spacesAfter.push(spaces); + return tag; + }); + + // Fetch nodes + var nodes; + if (tagNamesRequiringInnerHTMLFix[contextualElement.tagName.toLowerCase()]) { + // buildDOMWithFix uses string wrappers for problematic innerHTML. + nodes = buildDOMWithFix(html, contextualElement); + } else { + nodes = buildDOM(html, contextualElement, dom); + } + + // Build a list of script tags, the nodes themselves will be + // mutated as we add test nodes. + var i, j, node, nodeScriptNodes; + var scriptNodes = []; + for (i=0;node=nodes[i];i++) { + if (node.nodeType !== 1) { + continue; + } + if (node.tagName === 'SCRIPT') { + scriptNodes.push(node); + } else { + nodeScriptNodes = node.getElementsByTagName('script'); + for (j=0;j 0) { + textNode = dom.document.createTextNode(spaceBefore); + scriptNode.parentNode.insertBefore(textNode, scriptNode); + } + + spaceAfter = spacesAfter[i]; + if (spaceAfter && spaceAfter.length > 0) { + textNode = dom.document.createTextNode(spaceAfter); + scriptNode.parentNode.insertBefore(textNode, scriptNode.nextSibling); + } + } + + return nodes; + }; + } else { + buildIESafeDOM = buildDOM; + } + + var buildHTMLDOM; + if (needsIntegrationPointFix) { + buildHTMLDOM = function buildHTMLDOM(html, contextualElement, dom){ + if (svgHTMLIntegrationPoints[contextualElement.tagName]) { + return buildIESafeDOM(html, document.createElement('div'), dom); + } else { + return buildIESafeDOM(html, contextualElement, dom); + } + }; + } else { + buildHTMLDOM = buildIESafeDOM; + } + + __exports__.buildHTMLDOM = buildHTMLDOM; + }); +enifed("morph/morph", + ["exports"], + function(__exports__) { + "use strict"; + var splice = Array.prototype.splice; + + function ensureStartEnd(start, end) { + if (start === null || end === null) { + throw new Error('a fragment parent must have boundary nodes in order to detect insertion'); + } + } + + function ensureContext(contextualElement) { + if (!contextualElement || contextualElement.nodeType !== 1) { + throw new Error('An element node must be provided for a contextualElement, you provided ' + + (contextualElement ? 'nodeType ' + contextualElement.nodeType : 'nothing')); + } + } + + // TODO: this is an internal API, this should be an assert + function Morph(parent, start, end, domHelper, contextualElement) { + if (parent.nodeType === 11) { + ensureStartEnd(start, end); + this.element = null; + } else { + this.element = parent; + } + this._parent = parent; + this.start = start; + this.end = end; + this.domHelper = domHelper; + ensureContext(contextualElement); + this.contextualElement = contextualElement; + this.reset(); + } + + Morph.prototype.reset = function() { + this.text = null; + this.owner = null; + this.morphs = null; + this.before = null; + this.after = null; + this.escaped = true; + }; + + Morph.prototype.parent = function () { + if (!this.element) { + var parent = this.start.parentNode; + if (this._parent !== parent) { + this.element = this._parent = parent; + } + } + return this._parent; + }; + + Morph.prototype.destroy = function () { + if (this.owner) { + this.owner.removeMorph(this); + } else { + clear(this.element || this.parent(), this.start, this.end); + } + }; + + Morph.prototype.removeMorph = function (morph) { + var morphs = this.morphs; + for (var i=0, l=morphs.length; i 0 ? morphs[index-1] : null; + var after = index < morphs.length ? morphs[index] : null; + var start = before === null ? this.start : (before.end === null ? parent.lastChild : before.end.previousSibling); + var end = after === null ? this.end : (after.start === null ? parent.firstChild : after.start.nextSibling); + var morph = new Morph(parent, start, end, this.domHelper, this.contextualElement); + + morph.owner = this; + morph._update(parent, node); + + if (before !== null) { + morph.before = before; + before.end = start.nextSibling; + before.after = morph; + } + + if (after !== null) { + morph.after = after; + after.before = morph; + after.start = end.previousSibling; + } + + this.morphs.splice(index, 0, morph); + return morph; + }; + + Morph.prototype.replace = function (index, removedLength, addedNodes) { + if (this.morphs === null) this.morphs = []; + var parent = this.element || this.parent(); + var morphs = this.morphs; + var before = index > 0 ? morphs[index-1] : null; + var after = index+removedLength < morphs.length ? morphs[index+removedLength] : null; + var start = before === null ? this.start : (before.end === null ? parent.lastChild : before.end.previousSibling); + var end = after === null ? this.end : (after.start === null ? parent.firstChild : after.start.nextSibling); + var addedLength = addedNodes === undefined ? 0 : addedNodes.length; + var args, i, current; + + if (removedLength > 0) { + clear(parent, start, end); + } + + if (addedLength === 0) { + if (before !== null) { + before.after = after; + before.end = end; + } + if (after !== null) { + after.before = before; + after.start = start; + } + morphs.splice(index, removedLength); + return; + } + + args = new Array(addedLength+2); + if (addedLength > 0) { + for (i=0; i " + n.nextStates.map(function(s) { return s.debug() }).join(" or ") + " )"; + }).join(", ") + } + END IF **/ + + // This is a somewhat naive strategy, but should work in a lot of cases + // A better strategy would properly resolve /posts/:id/new and /posts/edit/:id. + // + // This strategy generally prefers more static and less dynamic matching. + // Specifically, it + // + // * prefers fewer stars to more, then + // * prefers using stars for less of the match to more, then + // * prefers fewer dynamic segments to more, then + // * prefers more static segments to more + function sortSolutions(states) { + return states.sort(function(a, b) { + if (a.types.stars !== b.types.stars) { return a.types.stars - b.types.stars; } + + if (a.types.stars) { + if (a.types.statics !== b.types.statics) { return b.types.statics - a.types.statics; } + if (a.types.dynamics !== b.types.dynamics) { return b.types.dynamics - a.types.dynamics; } + } + + if (a.types.dynamics !== b.types.dynamics) { return a.types.dynamics - b.types.dynamics; } + if (a.types.statics !== b.types.statics) { return b.types.statics - a.types.statics; } + + return 0; + }); + } + + function recognizeChar(states, ch) { + var nextStates = []; + + for (var i=0, l=states.length; i 2 && key.slice(keyLength -2) === '[]') { + isArray = true; + key = key.slice(0, keyLength - 2); + if(!queryParams[key]) { + queryParams[key] = []; + } + } + value = pair[1] ? decodeURIComponent(pair[1]) : ''; + } + if (isArray) { + queryParams[key].push(value); + } else { + queryParams[key] = value; + } + } + return queryParams; + }, + + recognize: function(path) { + var states = [ this.rootState ], + pathLen, i, l, queryStart, queryParams = {}, + isSlashDropped = false; + + queryStart = path.indexOf('?'); + if (queryStart !== -1) { + var queryString = path.substr(queryStart + 1, path.length); + path = path.substr(0, queryStart); + queryParams = this.parseQueryString(queryString); + } + + path = decodeURI(path); + + // DEBUG GROUP path + + if (path.charAt(0) !== "/") { path = "/" + path; } + + pathLen = path.length; + if (pathLen > 1 && path.charAt(pathLen - 1) === "/") { + path = path.substr(0, pathLen - 1); + isSlashDropped = true; + } + + for (i=0, l=path.length; i= 0 && proceed; --i) { + var route = routes[i]; + recognizer.add(routes, { as: route.handler }); + proceed = route.path === '/' || route.path === '' || route.handler.slice(-6) === '.index'; + } + }); + }, + + hasRoute: function(route) { + return this.recognizer.hasRoute(route); + }, + + queryParamsTransition: function(changelist, wasTransitioning, oldState, newState) { + var router = this; + + fireQueryParamDidChange(this, newState, changelist); + + if (!wasTransitioning && this.activeTransition) { + // One of the handlers in queryParamsDidChange + // caused a transition. Just return that transition. + return this.activeTransition; + } else { + // Running queryParamsDidChange didn't change anything. + // Just update query params and be on our way. + + // We have to return a noop transition that will + // perform a URL update at the end. This gives + // the user the ability to set the url update + // method (default is replaceState). + var newTransition = new Transition(this); + newTransition.queryParamsOnly = true; + + oldState.queryParams = finalizeQueryParamChange(this, newState.handlerInfos, newState.queryParams, newTransition); + + newTransition.promise = newTransition.promise.then(function(result) { + updateURL(newTransition, oldState, true); + if (router.didTransition) { + router.didTransition(router.currentHandlerInfos); + } + return result; + }, null, promiseLabel("Transition complete")); + return newTransition; + } + }, + + // NOTE: this doesn't really belong here, but here + // it shall remain until our ES6 transpiler can + // handle cyclical deps. + transitionByIntent: function(intent, isIntermediate) { + try { + return getTransitionByIntent.apply(this, arguments); + } catch(e) { + return new Transition(this, intent, null, e); + } + }, + + /** + Clears the current and target route handlers and triggers exit + on each of them starting at the leaf and traversing up through + its ancestors. + */ + reset: function() { + if (this.state) { + forEach(this.state.handlerInfos.slice().reverse(), function(handlerInfo) { + var handler = handlerInfo.handler; + callHook(handler, 'exit'); + }); + } + + this.state = new TransitionState(); + this.currentHandlerInfos = null; + }, + + activeTransition: null, + + /** + var handler = handlerInfo.handler; + The entry point for handling a change to the URL (usually + via the back and forward button). + + Returns an Array of handlers and the parameters associated + with those parameters. + + @param {String} url a URL to process + + @return {Array} an Array of `[handler, parameter]` tuples + */ + handleURL: function(url) { + // Perform a URL-based transition, but don't change + // the URL afterward, since it already happened. + var args = slice.call(arguments); + if (url.charAt(0) !== '/') { args[0] = '/' + url; } + + return doTransition(this, args).method(null); + }, + + /** + Hook point for updating the URL. + + @param {String} url a URL to update to + */ + updateURL: function() { + throw new Error("updateURL is not implemented"); + }, + + /** + Hook point for replacing the current URL, i.e. with replaceState + + By default this behaves the same as `updateURL` + + @param {String} url a URL to update to + */ + replaceURL: function(url) { + this.updateURL(url); + }, + + /** + Transition into the specified named route. + + If necessary, trigger the exit callback on any handlers + that are no longer represented by the target route. + + @param {String} name the name of the route + */ + transitionTo: function(name) { + return doTransition(this, arguments); + }, + + intermediateTransitionTo: function(name) { + return doTransition(this, arguments, true); + }, + + refresh: function(pivotHandler) { + var state = this.activeTransition ? this.activeTransition.state : this.state; + var handlerInfos = state.handlerInfos; + var params = {}; + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var handlerInfo = handlerInfos[i]; + params[handlerInfo.name] = handlerInfo.params || {}; + } + + log(this, "Starting a refresh transition"); + var intent = new NamedTransitionIntent({ + name: handlerInfos[handlerInfos.length - 1].name, + pivotHandler: pivotHandler || handlerInfos[0].handler, + contexts: [], // TODO collect contexts...? + queryParams: this._changedQueryParams || state.queryParams || {} + }); + + return this.transitionByIntent(intent, false); + }, + + /** + Identical to `transitionTo` except that the current URL will be replaced + if possible. + + This method is intended primarily for use with `replaceState`. + + @param {String} name the name of the route + */ + replaceWith: function(name) { + return doTransition(this, arguments).method('replace'); + }, + + /** + Take a named route and context objects and generate a + URL. + + @param {String} name the name of the route to generate + a URL for + @param {...Object} objects a list of objects to serialize + + @return {String} a URL + */ + generate: function(handlerName) { + + var partitionedArgs = extractQueryParams(slice.call(arguments, 1)), + suppliedParams = partitionedArgs[0], + queryParams = partitionedArgs[1]; + + // Construct a TransitionIntent with the provided params + // and apply it to the present state of the router. + var intent = new NamedTransitionIntent({ name: handlerName, contexts: suppliedParams }); + var state = intent.applyToState(this.state, this.recognizer, this.getHandler); + var params = {}; + + for (var i = 0, len = state.handlerInfos.length; i < len; ++i) { + var handlerInfo = state.handlerInfos[i]; + var handlerParams = handlerInfo.serialize(); + merge(params, handlerParams); + } + params.queryParams = queryParams; + + return this.recognizer.generate(handlerName, params); + }, + + applyIntent: function(handlerName, contexts) { + var intent = new NamedTransitionIntent({ + name: handlerName, + contexts: contexts + }); + + var state = this.activeTransition && this.activeTransition.state || this.state; + return intent.applyToState(state, this.recognizer, this.getHandler); + }, + + isActiveIntent: function(handlerName, contexts, queryParams) { + var targetHandlerInfos = this.state.handlerInfos, + found = false, names, object, handlerInfo, handlerObj, i, len; + + if (!targetHandlerInfos.length) { return false; } + + var targetHandler = targetHandlerInfos[targetHandlerInfos.length - 1].name; + var recogHandlers = this.recognizer.handlersFor(targetHandler); + + var index = 0; + for (len = recogHandlers.length; index < len; ++index) { + handlerInfo = targetHandlerInfos[index]; + if (handlerInfo.name === handlerName) { break; } + } + + if (index === recogHandlers.length) { + // The provided route name isn't even in the route hierarchy. + return false; + } + + var state = new TransitionState(); + state.handlerInfos = targetHandlerInfos.slice(0, index + 1); + recogHandlers = recogHandlers.slice(0, index + 1); + + var intent = new NamedTransitionIntent({ + name: targetHandler, + contexts: contexts + }); + + var newState = intent.applyToHandlers(state, recogHandlers, this.getHandler, targetHandler, true, true); + + var handlersEqual = handlerInfosEqual(newState.handlerInfos, state.handlerInfos); + if (!queryParams || !handlersEqual) { + return handlersEqual; + } + + // Get a hash of QPs that will still be active on new route + var activeQPsOnNewHandler = {}; + merge(activeQPsOnNewHandler, queryParams); + + var activeQueryParams = this.state.queryParams; + for (var key in activeQueryParams) { + if (activeQueryParams.hasOwnProperty(key) && + activeQPsOnNewHandler.hasOwnProperty(key)) { + activeQPsOnNewHandler[key] = activeQueryParams[key]; + } + } + + return handlersEqual && !getChangelist(activeQPsOnNewHandler, queryParams); + }, + + isActive: function(handlerName) { + var partitionedArgs = extractQueryParams(slice.call(arguments, 1)); + return this.isActiveIntent(handlerName, partitionedArgs[0], partitionedArgs[1]); + }, + + trigger: function(name) { + var args = slice.call(arguments); + trigger(this, this.currentHandlerInfos, false, args); + }, + + /** + Hook point for logging transition status updates. + + @param {String} message The message to log. + */ + log: null, + + _willChangeContextEvent: 'willChangeContext', + _triggerWillChangeContext: function(handlerInfos, newTransition) { + trigger(this, handlerInfos, true, [this._willChangeContextEvent, newTransition]); + }, + + _triggerWillLeave: function(handlerInfos, newTransition, leavingChecker) { + trigger(this, handlerInfos, true, ['willLeave', newTransition, leavingChecker]); + } + }; + + /** + @private + + Fires queryParamsDidChange event + */ + function fireQueryParamDidChange(router, newState, queryParamChangelist) { + // If queryParams changed trigger event + if (queryParamChangelist) { + + // This is a little hacky but we need some way of storing + // changed query params given that no activeTransition + // is guaranteed to have occurred. + router._changedQueryParams = queryParamChangelist.all; + trigger(router, newState.handlerInfos, true, ['queryParamsDidChange', queryParamChangelist.changed, queryParamChangelist.all, queryParamChangelist.removed]); + router._changedQueryParams = null; + } + } + + /** + @private + + Takes an Array of `HandlerInfo`s, figures out which ones are + exiting, entering, or changing contexts, and calls the + proper handler hooks. + + For example, consider the following tree of handlers. Each handler is + followed by the URL segment it handles. + + ``` + |~index ("/") + | |~posts ("/posts") + | | |-showPost ("/:id") + | | |-newPost ("/new") + | | |-editPost ("/edit") + | |~about ("/about/:id") + ``` + + Consider the following transitions: + + 1. A URL transition to `/posts/1`. + 1. Triggers the `*model` callbacks on the + `index`, `posts`, and `showPost` handlers + 2. Triggers the `enter` callback on the same + 3. Triggers the `setup` callback on the same + 2. A direct transition to `newPost` + 1. Triggers the `exit` callback on `showPost` + 2. Triggers the `enter` callback on `newPost` + 3. Triggers the `setup` callback on `newPost` + 3. A direct transition to `about` with a specified + context object + 1. Triggers the `exit` callback on `newPost` + and `posts` + 2. Triggers the `serialize` callback on `about` + 3. Triggers the `enter` callback on `about` + 4. Triggers the `setup` callback on `about` + + @param {Router} transition + @param {TransitionState} newState + */ + function setupContexts(router, newState, transition) { + var partition = partitionHandlers(router.state, newState); + + forEach(partition.exited, function(handlerInfo) { + var handler = handlerInfo.handler; + delete handler.context; + + callHook(handler, 'reset', true, transition); + callHook(handler, 'exit', transition); + }); + + var oldState = router.oldState = router.state; + router.state = newState; + var currentHandlerInfos = router.currentHandlerInfos = partition.unchanged.slice(); + + try { + forEach(partition.reset, function(handlerInfo) { + var handler = handlerInfo.handler; + callHook(handler, 'reset', false, transition); + }); + + forEach(partition.updatedContext, function(handlerInfo) { + return handlerEnteredOrUpdated(currentHandlerInfos, handlerInfo, false, transition); + }); + + forEach(partition.entered, function(handlerInfo) { + return handlerEnteredOrUpdated(currentHandlerInfos, handlerInfo, true, transition); + }); + } catch(e) { + router.state = oldState; + router.currentHandlerInfos = oldState.handlerInfos; + throw e; + } + + router.state.queryParams = finalizeQueryParamChange(router, currentHandlerInfos, newState.queryParams, transition); + } + + + /** + @private + + Helper method used by setupContexts. Handles errors or redirects + that may happen in enter/setup. + */ + function handlerEnteredOrUpdated(currentHandlerInfos, handlerInfo, enter, transition) { + + var handler = handlerInfo.handler, + context = handlerInfo.context; + + if (enter) { + callHook(handler, 'enter', transition); + } + if (transition && transition.isAborted) { + throw new TransitionAborted(); + } + + handler.context = context; + callHook(handler, 'contextDidChange'); + + callHook(handler, 'setup', context, transition); + if (transition && transition.isAborted) { + throw new TransitionAborted(); + } + + currentHandlerInfos.push(handlerInfo); + + return true; + } + + + /** + @private + + This function is called when transitioning from one URL to + another to determine which handlers are no longer active, + which handlers are newly active, and which handlers remain + active but have their context changed. + + Take a list of old handlers and new handlers and partition + them into four buckets: + + * unchanged: the handler was active in both the old and + new URL, and its context remains the same + * updated context: the handler was active in both the + old and new URL, but its context changed. The handler's + `setup` method, if any, will be called with the new + context. + * exited: the handler was active in the old URL, but is + no longer active. + * entered: the handler was not active in the old URL, but + is now active. + + The PartitionedHandlers structure has four fields: + + * `updatedContext`: a list of `HandlerInfo` objects that + represent handlers that remain active but have a changed + context + * `entered`: a list of `HandlerInfo` objects that represent + handlers that are newly active + * `exited`: a list of `HandlerInfo` objects that are no + longer active. + * `unchanged`: a list of `HanderInfo` objects that remain active. + + @param {Array[HandlerInfo]} oldHandlers a list of the handler + information for the previous URL (or `[]` if this is the + first handled transition) + @param {Array[HandlerInfo]} newHandlers a list of the handler + information for the new URL + + @return {Partition} + */ + function partitionHandlers(oldState, newState) { + var oldHandlers = oldState.handlerInfos; + var newHandlers = newState.handlerInfos; + + var handlers = { + updatedContext: [], + exited: [], + entered: [], + unchanged: [] + }; + + var handlerChanged, contextChanged = false, i, l; + + for (i=0, l=newHandlers.length; i= 0; --i) { + var handlerInfo = handlerInfos[i]; + merge(params, handlerInfo.params); + if (handlerInfo.handler.inaccessibleByURL) { + urlMethod = null; + } + } + + if (urlMethod) { + params.queryParams = transition._visibleQueryParams || state.queryParams; + var url = router.recognizer.generate(handlerName, params); + + if (urlMethod === 'replace') { + router.replaceURL(url); + } else { + router.updateURL(url); + } + } + } + + /** + @private + + Updates the URL (if necessary) and calls `setupContexts` + to update the router's array of `currentHandlerInfos`. + */ + function finalizeTransition(transition, newState) { + + try { + log(transition.router, transition.sequence, "Resolved all models on destination route; finalizing transition."); + + var router = transition.router, + handlerInfos = newState.handlerInfos, + seq = transition.sequence; + + // Run all the necessary enter/setup/exit hooks + setupContexts(router, newState, transition); + + // Check if a redirect occurred in enter/setup + if (transition.isAborted) { + // TODO: cleaner way? distinguish b/w targetHandlerInfos? + router.state.handlerInfos = router.currentHandlerInfos; + return Promise.reject(logAbort(transition)); + } + + updateURL(transition, newState, transition.intent.url); + + transition.isActive = false; + router.activeTransition = null; + + trigger(router, router.currentHandlerInfos, true, ['didTransition']); + + if (router.didTransition) { + router.didTransition(router.currentHandlerInfos); + } + + log(router, transition.sequence, "TRANSITION COMPLETE."); + + // Resolve with the final handler. + return handlerInfos[handlerInfos.length - 1].handler; + } catch(e) { + if (!((e instanceof TransitionAborted))) { + //var erroneousHandler = handlerInfos.pop(); + var infos = transition.state.handlerInfos; + transition.trigger(true, 'error', e, transition, infos[infos.length-1].handler); + transition.abort(); + } + + throw e; + } + } + + /** + @private + + Begins and returns a Transition based on the provided + arguments. Accepts arguments in the form of both URL + transitions and named transitions. + + @param {Router} router + @param {Array[Object]} args arguments passed to transitionTo, + replaceWith, or handleURL + */ + function doTransition(router, args, isIntermediate) { + // Normalize blank transitions to root URL transitions. + var name = args[0] || '/'; + + var lastArg = args[args.length-1]; + var queryParams = {}; + if (lastArg && lastArg.hasOwnProperty('queryParams')) { + queryParams = pop.call(args).queryParams; + } + + var intent; + if (args.length === 0) { + + log(router, "Updating query params"); + + // A query param update is really just a transition + // into the route you're already on. + var handlerInfos = router.state.handlerInfos; + intent = new NamedTransitionIntent({ + name: handlerInfos[handlerInfos.length - 1].name, + contexts: [], + queryParams: queryParams + }); + + } else if (name.charAt(0) === '/') { + + log(router, "Attempting URL transition to " + name); + intent = new URLTransitionIntent({ url: name }); + + } else { + + log(router, "Attempting transition to " + name); + intent = new NamedTransitionIntent({ + name: args[0], + contexts: slice.call(args, 1), + queryParams: queryParams + }); + } + + return router.transitionByIntent(intent, isIntermediate); + } + + function handlerInfosEqual(handlerInfos, otherHandlerInfos) { + if (handlerInfos.length !== otherHandlerInfos.length) { + return false; + } + + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + if (handlerInfos[i] !== otherHandlerInfos[i]) { + return false; + } + } + return true; + } + + function finalizeQueryParamChange(router, resolvedHandlers, newQueryParams, transition) { + // We fire a finalizeQueryParamChange event which + // gives the new route hierarchy a chance to tell + // us which query params it's consuming and what + // their final values are. If a query param is + // no longer consumed in the final route hierarchy, + // its serialized segment will be removed + // from the URL. + + for (var k in newQueryParams) { + if (newQueryParams.hasOwnProperty(k) && + newQueryParams[k] === null) { + delete newQueryParams[k]; + } + } + + var finalQueryParamsArray = []; + trigger(router, resolvedHandlers, true, ['finalizeQueryParamChange', newQueryParams, finalQueryParamsArray, transition]); + + if (transition) { + transition._visibleQueryParams = {}; + } + + var finalQueryParams = {}; + for (var i = 0, len = finalQueryParamsArray.length; i < len; ++i) { + var qp = finalQueryParamsArray[i]; + finalQueryParams[qp.key] = qp.value; + if (transition && qp.visible !== false) { + transition._visibleQueryParams[qp.key] = qp.value; + } + } + return finalQueryParams; + } + + function notifyExistingHandlers(router, newState, newTransition) { + var oldHandlers = router.state.handlerInfos, + changing = [], + leavingIndex = null, + leaving, leavingChecker, i, oldHandlerLen, oldHandler, newHandler; + + oldHandlerLen = oldHandlers.length; + for (i = 0; i < oldHandlerLen; i++) { + oldHandler = oldHandlers[i]; + newHandler = newState.handlerInfos[i]; + + if (!newHandler || oldHandler.name !== newHandler.name) { + leavingIndex = i; + break; + } + + if (!newHandler.isResolved) { + changing.push(oldHandler); + } + } + + if (leavingIndex !== null) { + leaving = oldHandlers.slice(leavingIndex, oldHandlerLen); + leavingChecker = function(name) { + for (var h = 0, len = leaving.length; h < len; h++) { + if (leaving[h].name === name) { + return true; + } + } + return false; + }; + + router._triggerWillLeave(leaving, newTransition, leavingChecker); + } + + if (changing.length > 0) { + router._triggerWillChangeContext(changing, newTransition); + } + + trigger(router, oldHandlers, true, ['willTransition', newTransition]); + } + + __exports__["default"] = Router; + }); +enifed("router/transition-intent", + ["./utils","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var merge = __dependency1__.merge; + + function TransitionIntent(props) { + this.initialize(props); + + // TODO: wat + this.data = this.data || {}; + } + + TransitionIntent.prototype = { + initialize: null, + applyToState: null + }; + + __exports__["default"] = TransitionIntent; + }); +enifed("router/transition-intent/named-transition-intent", + ["../transition-intent","../transition-state","../handler-info/factory","../utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var TransitionIntent = __dependency1__["default"]; + var TransitionState = __dependency2__["default"]; + var handlerInfoFactory = __dependency3__["default"]; + var isParam = __dependency4__.isParam; + var extractQueryParams = __dependency4__.extractQueryParams; + var merge = __dependency4__.merge; + var subclass = __dependency4__.subclass; + + __exports__["default"] = subclass(TransitionIntent, { + name: null, + pivotHandler: null, + contexts: null, + queryParams: null, + + initialize: function(props) { + this.name = props.name; + this.pivotHandler = props.pivotHandler; + this.contexts = props.contexts || []; + this.queryParams = props.queryParams; + }, + + applyToState: function(oldState, recognizer, getHandler, isIntermediate) { + + var partitionedArgs = extractQueryParams([this.name].concat(this.contexts)), + pureArgs = partitionedArgs[0], + queryParams = partitionedArgs[1], + handlers = recognizer.handlersFor(pureArgs[0]); + + var targetRouteName = handlers[handlers.length-1].handler; + + return this.applyToHandlers(oldState, handlers, getHandler, targetRouteName, isIntermediate); + }, + + applyToHandlers: function(oldState, handlers, getHandler, targetRouteName, isIntermediate, checkingIfActive) { + + var i, len; + var newState = new TransitionState(); + var objects = this.contexts.slice(0); + + var invalidateIndex = handlers.length; + + // Pivot handlers are provided for refresh transitions + if (this.pivotHandler) { + for (i = 0, len = handlers.length; i < len; ++i) { + if (getHandler(handlers[i].handler) === this.pivotHandler) { + invalidateIndex = i; + break; + } + } + } + + var pivotHandlerFound = !this.pivotHandler; + + for (i = handlers.length - 1; i >= 0; --i) { + var result = handlers[i]; + var name = result.handler; + var handler = getHandler(name); + + var oldHandlerInfo = oldState.handlerInfos[i]; + var newHandlerInfo = null; + + if (result.names.length > 0) { + if (i >= invalidateIndex) { + newHandlerInfo = this.createParamHandlerInfo(name, handler, result.names, objects, oldHandlerInfo); + } else { + newHandlerInfo = this.getHandlerInfoForDynamicSegment(name, handler, result.names, objects, oldHandlerInfo, targetRouteName, i); + } + } else { + // This route has no dynamic segment. + // Therefore treat as a param-based handlerInfo + // with empty params. This will cause the `model` + // hook to be called with empty params, which is desirable. + newHandlerInfo = this.createParamHandlerInfo(name, handler, result.names, objects, oldHandlerInfo); + } + + if (checkingIfActive) { + // If we're performing an isActive check, we want to + // serialize URL params with the provided context, but + // ignore mismatches between old and new context. + newHandlerInfo = newHandlerInfo.becomeResolved(null, newHandlerInfo.context); + var oldContext = oldHandlerInfo && oldHandlerInfo.context; + if (result.names.length > 0 && newHandlerInfo.context === oldContext) { + // If contexts match in isActive test, assume params also match. + // This allows for flexibility in not requiring that every last + // handler provide a `serialize` method + newHandlerInfo.params = oldHandlerInfo && oldHandlerInfo.params; + } + newHandlerInfo.context = oldContext; + } + + var handlerToUse = oldHandlerInfo; + if (i >= invalidateIndex || newHandlerInfo.shouldSupercede(oldHandlerInfo)) { + invalidateIndex = Math.min(i, invalidateIndex); + handlerToUse = newHandlerInfo; + } + + if (isIntermediate && !checkingIfActive) { + handlerToUse = handlerToUse.becomeResolved(null, handlerToUse.context); + } + + newState.handlerInfos.unshift(handlerToUse); + } + + if (objects.length > 0) { + throw new Error("More context objects were passed than there are dynamic segments for the route: " + targetRouteName); + } + + if (!isIntermediate) { + this.invalidateChildren(newState.handlerInfos, invalidateIndex); + } + + merge(newState.queryParams, this.queryParams || {}); + + return newState; + }, + + invalidateChildren: function(handlerInfos, invalidateIndex) { + for (var i = invalidateIndex, l = handlerInfos.length; i < l; ++i) { + var handlerInfo = handlerInfos[i]; + handlerInfos[i] = handlerInfos[i].getUnresolved(); + } + }, + + getHandlerInfoForDynamicSegment: function(name, handler, names, objects, oldHandlerInfo, targetRouteName, i) { + + var numNames = names.length; + var objectToUse; + if (objects.length > 0) { + + // Use the objects provided for this transition. + objectToUse = objects[objects.length - 1]; + if (isParam(objectToUse)) { + return this.createParamHandlerInfo(name, handler, names, objects, oldHandlerInfo); + } else { + objects.pop(); + } + } else if (oldHandlerInfo && oldHandlerInfo.name === name) { + // Reuse the matching oldHandlerInfo + return oldHandlerInfo; + } else { + if (this.preTransitionState) { + var preTransitionHandlerInfo = this.preTransitionState.handlerInfos[i]; + objectToUse = preTransitionHandlerInfo && preTransitionHandlerInfo.context; + } else { + // Ideally we should throw this error to provide maximal + // information to the user that not enough context objects + // were provided, but this proves too cumbersome in Ember + // in cases where inner template helpers are evaluated + // before parent helpers un-render, in which cases this + // error somewhat prematurely fires. + //throw new Error("Not enough context objects were provided to complete a transition to " + targetRouteName + ". Specifically, the " + name + " route needs an object that can be serialized into its dynamic URL segments [" + names.join(', ') + "]"); + return oldHandlerInfo; + } + } + + return handlerInfoFactory('object', { + name: name, + handler: handler, + context: objectToUse, + names: names + }); + }, + + createParamHandlerInfo: function(name, handler, names, objects, oldHandlerInfo) { + var params = {}; + + // Soak up all the provided string/numbers + var numNames = names.length; + while (numNames--) { + + // Only use old params if the names match with the new handler + var oldParams = (oldHandlerInfo && name === oldHandlerInfo.name && oldHandlerInfo.params) || {}; + + var peek = objects[objects.length - 1]; + var paramName = names[numNames]; + if (isParam(peek)) { + params[paramName] = "" + objects.pop(); + } else { + // If we're here, this means only some of the params + // were string/number params, so try and use a param + // value from a previous handler. + if (oldParams.hasOwnProperty(paramName)) { + params[paramName] = oldParams[paramName]; + } else { + throw new Error("You didn't provide enough string/numeric parameters to satisfy all of the dynamic segments for route " + name); + } + } + } + + return handlerInfoFactory('param', { + name: name, + handler: handler, + params: params + }); + } + }); + }); +enifed("router/transition-intent/url-transition-intent", + ["../transition-intent","../transition-state","../handler-info/factory","../utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var TransitionIntent = __dependency1__["default"]; + var TransitionState = __dependency2__["default"]; + var handlerInfoFactory = __dependency3__["default"]; + var oCreate = __dependency4__.oCreate; + var merge = __dependency4__.merge; + var subclass = __dependency4__.subclass; + + __exports__["default"] = subclass(TransitionIntent, { + url: null, + + initialize: function(props) { + this.url = props.url; + }, + + applyToState: function(oldState, recognizer, getHandler) { + var newState = new TransitionState(); + + var results = recognizer.recognize(this.url), + queryParams = {}, + i, len; + + if (!results) { + throw new UnrecognizedURLError(this.url); + } + + var statesDiffer = false; + + for (i = 0, len = results.length; i < len; ++i) { + var result = results[i]; + var name = result.handler; + var handler = getHandler(name); + + if (handler.inaccessibleByURL) { + throw new UnrecognizedURLError(this.url); + } + + var newHandlerInfo = handlerInfoFactory('param', { + name: name, + handler: handler, + params: result.params + }); + + var oldHandlerInfo = oldState.handlerInfos[i]; + if (statesDiffer || newHandlerInfo.shouldSupercede(oldHandlerInfo)) { + statesDiffer = true; + newState.handlerInfos[i] = newHandlerInfo; + } else { + newState.handlerInfos[i] = oldHandlerInfo; + } + } + + merge(newState.queryParams, results.queryParams); + + return newState; + } + }); + + /** + Promise reject reasons passed to promise rejection + handlers for failed transitions. + */ + function UnrecognizedURLError(message) { + this.message = (message || "UnrecognizedURLError"); + this.name = "UnrecognizedURLError"; + } + }); +enifed("router/transition-state", + ["./handler-info","./utils","rsvp/promise","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var ResolvedHandlerInfo = __dependency1__.ResolvedHandlerInfo; + var forEach = __dependency2__.forEach; + var promiseLabel = __dependency2__.promiseLabel; + var callHook = __dependency2__.callHook; + var Promise = __dependency3__["default"]; + + function TransitionState(other) { + this.handlerInfos = []; + this.queryParams = {}; + this.params = {}; + } + + TransitionState.prototype = { + handlerInfos: null, + queryParams: null, + params: null, + + promiseLabel: function(label) { + var targetName = ''; + forEach(this.handlerInfos, function(handlerInfo) { + if (targetName !== '') { + targetName += '.'; + } + targetName += handlerInfo.name; + }); + return promiseLabel("'" + targetName + "': " + label); + }, + + resolve: function(shouldContinue, payload) { + var self = this; + // First, calculate params for this state. This is useful + // information to provide to the various route hooks. + var params = this.params; + forEach(this.handlerInfos, function(handlerInfo) { + params[handlerInfo.name] = handlerInfo.params || {}; + }); + + payload = payload || {}; + payload.resolveIndex = 0; + + var currentState = this; + var wasAborted = false; + + // The prelude RSVP.resolve() asyncs us into the promise land. + return Promise.resolve(null, this.promiseLabel("Start transition")) + .then(resolveOneHandlerInfo, null, this.promiseLabel('Resolve handler'))['catch'](handleError, this.promiseLabel('Handle error')); + + function innerShouldContinue() { + return Promise.resolve(shouldContinue(), currentState.promiseLabel("Check if should continue"))['catch'](function(reason) { + // We distinguish between errors that occurred + // during resolution (e.g. beforeModel/model/afterModel), + // and aborts due to a rejecting promise from shouldContinue(). + wasAborted = true; + return Promise.reject(reason); + }, currentState.promiseLabel("Handle abort")); + } + + function handleError(error) { + // This is the only possible + // reject value of TransitionState#resolve + var handlerInfos = currentState.handlerInfos; + var errorHandlerIndex = payload.resolveIndex >= handlerInfos.length ? + handlerInfos.length - 1 : payload.resolveIndex; + return Promise.reject({ + error: error, + handlerWithError: currentState.handlerInfos[errorHandlerIndex].handler, + wasAborted: wasAborted, + state: currentState + }); + } + + function proceed(resolvedHandlerInfo) { + var wasAlreadyResolved = currentState.handlerInfos[payload.resolveIndex].isResolved; + + // Swap the previously unresolved handlerInfo with + // the resolved handlerInfo + currentState.handlerInfos[payload.resolveIndex++] = resolvedHandlerInfo; + + if (!wasAlreadyResolved) { + // Call the redirect hook. The reason we call it here + // vs. afterModel is so that redirects into child + // routes don't re-run the model hooks for this + // already-resolved route. + var handler = resolvedHandlerInfo.handler; + callHook(handler, 'redirect', resolvedHandlerInfo.context, payload); + } + + // Proceed after ensuring that the redirect hook + // didn't abort this transition by transitioning elsewhere. + return innerShouldContinue().then(resolveOneHandlerInfo, null, currentState.promiseLabel('Resolve handler')); + } + + function resolveOneHandlerInfo() { + if (payload.resolveIndex === currentState.handlerInfos.length) { + // This is is the only possible + // fulfill value of TransitionState#resolve + return { + error: null, + state: currentState + }; + } + + var handlerInfo = currentState.handlerInfos[payload.resolveIndex]; + + return handlerInfo.resolve(innerShouldContinue, payload) + .then(proceed, null, currentState.promiseLabel('Proceed')); + } + } + }; + + __exports__["default"] = TransitionState; + }); +enifed("router/transition", + ["rsvp/promise","./handler-info","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var ResolvedHandlerInfo = __dependency2__.ResolvedHandlerInfo; + var trigger = __dependency3__.trigger; + var slice = __dependency3__.slice; + var log = __dependency3__.log; + var promiseLabel = __dependency3__.promiseLabel; + + /** + @private + + A Transition is a thennable (a promise-like object) that represents + an attempt to transition to another route. It can be aborted, either + explicitly via `abort` or by attempting another transition while a + previous one is still underway. An aborted transition can also + be `retry()`d later. + */ + function Transition(router, intent, state, error) { + var transition = this; + this.state = state || router.state; + this.intent = intent; + this.router = router; + this.data = this.intent && this.intent.data || {}; + this.resolvedModels = {}; + this.queryParams = {}; + + if (error) { + this.promise = Promise.reject(error); + return; + } + + if (state) { + this.params = state.params; + this.queryParams = state.queryParams; + this.handlerInfos = state.handlerInfos; + + var len = state.handlerInfos.length; + if (len) { + this.targetName = state.handlerInfos[len-1].name; + } + + for (var i = 0; i < len; ++i) { + var handlerInfo = state.handlerInfos[i]; + + // TODO: this all seems hacky + if (!handlerInfo.isResolved) { break; } + this.pivotHandler = handlerInfo.handler; + } + + this.sequence = Transition.currentSequence++; + this.promise = state.resolve(checkForAbort, this)['catch'](function(result) { + if (result.wasAborted || transition.isAborted) { + return Promise.reject(logAbort(transition)); + } else { + transition.trigger('error', result.error, transition, result.handlerWithError); + transition.abort(); + return Promise.reject(result.error); + } + }, promiseLabel('Handle Abort')); + } else { + this.promise = Promise.resolve(this.state); + this.params = {}; + } + + function checkForAbort() { + if (transition.isAborted) { + return Promise.reject(undefined, promiseLabel("Transition aborted - reject")); + } + } + } + + Transition.currentSequence = 0; + + Transition.prototype = { + targetName: null, + urlMethod: 'update', + intent: null, + params: null, + pivotHandler: null, + resolveIndex: 0, + handlerInfos: null, + resolvedModels: null, + isActive: true, + state: null, + queryParamsOnly: false, + + isTransition: true, + + isExiting: function(handler) { + var handlerInfos = this.handlerInfos; + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var handlerInfo = handlerInfos[i]; + if (handlerInfo.name === handler || handlerInfo.handler === handler) { + return false; + } + } + return true; + }, + + /** + @public + + The Transition's internal promise. Calling `.then` on this property + is that same as calling `.then` on the Transition object itself, but + this property is exposed for when you want to pass around a + Transition's promise, but not the Transition object itself, since + Transition object can be externally `abort`ed, while the promise + cannot. + */ + promise: null, + + /** + @public + + Custom state can be stored on a Transition's `data` object. + This can be useful for decorating a Transition within an earlier + hook and shared with a later hook. Properties set on `data` will + be copied to new transitions generated by calling `retry` on this + transition. + */ + data: null, + + /** + @public + + A standard promise hook that resolves if the transition + succeeds and rejects if it fails/redirects/aborts. + + Forwards to the internal `promise` property which you can + use in situations where you want to pass around a thennable, + but not the Transition itself. + + @param {Function} onFulfilled + @param {Function} onRejected + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + then: function(onFulfilled, onRejected, label) { + return this.promise.then(onFulfilled, onRejected, label); + }, + + /** + @public + + Forwards to the internal `promise` property which you can + use in situations where you want to pass around a thennable, + but not the Transition itself. + + @method catch + @param {Function} onRejection + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + "catch": function(onRejection, label) { + return this.promise["catch"](onRejection, label); + }, + + /** + @public + + Forwards to the internal `promise` property which you can + use in situations where you want to pass around a thennable, + but not the Transition itself. + + @method finally + @param {Function} callback + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + "finally": function(callback, label) { + return this.promise["finally"](callback, label); + }, + + /** + @public + + Aborts the Transition. Note you can also implicitly abort a transition + by initiating another transition while a previous one is underway. + */ + abort: function() { + if (this.isAborted) { return this; } + log(this.router, this.sequence, this.targetName + ": transition was aborted"); + this.intent.preTransitionState = this.router.state; + this.isAborted = true; + this.isActive = false; + this.router.activeTransition = null; + return this; + }, + + /** + @public + + Retries a previously-aborted transition (making sure to abort the + transition if it's still active). Returns a new transition that + represents the new attempt to transition. + */ + retry: function() { + // TODO: add tests for merged state retry()s + this.abort(); + return this.router.transitionByIntent(this.intent, false); + }, + + /** + @public + + Sets the URL-changing method to be employed at the end of a + successful transition. By default, a new Transition will just + use `updateURL`, but passing 'replace' to this method will + cause the URL to update using 'replaceWith' instead. Omitting + a parameter will disable the URL change, allowing for transitions + that don't update the URL at completion (this is also used for + handleURL, since the URL has already changed before the + transition took place). + + @param {String} method the type of URL-changing method to use + at the end of a transition. Accepted values are 'replace', + falsy values, or any other non-falsy value (which is + interpreted as an updateURL transition). + + @return {Transition} this transition + */ + method: function(method) { + this.urlMethod = method; + return this; + }, + + /** + @public + + Fires an event on the current list of resolved/resolving + handlers within this transition. Useful for firing events + on route hierarchies that haven't fully been entered yet. + + Note: This method is also aliased as `send` + + @param {Boolean} [ignoreFailure=false] a boolean specifying whether unhandled events throw an error + @param {String} name the name of the event to fire + */ + trigger: function (ignoreFailure) { + var args = slice.call(arguments); + if (typeof ignoreFailure === 'boolean') { + args.shift(); + } else { + // Throw errors on unhandled trigger events by default + ignoreFailure = false; + } + trigger(this.router, this.state.handlerInfos.slice(0, this.resolveIndex + 1), ignoreFailure, args); + }, + + /** + @public + + Transitions are aborted and their promises rejected + when redirects occur; this method returns a promise + that will follow any redirects that occur and fulfill + with the value fulfilled by any redirecting transitions + that occur. + + @return {Promise} a promise that fulfills with the same + value that the final redirecting transition fulfills with + */ + followRedirects: function() { + var router = this.router; + return this.promise['catch'](function(reason) { + if (router.activeTransition) { + return router.activeTransition.followRedirects(); + } + return Promise.reject(reason); + }); + }, + + toString: function() { + return "Transition (sequence " + this.sequence + ")"; + }, + + /** + @private + */ + log: function(message) { + log(this.router, this.sequence, message); + } + }; + + // Alias 'trigger' as 'send' + Transition.prototype.send = Transition.prototype.trigger; + + /** + @private + + Logs and returns a TransitionAborted error. + */ + function logAbort(transition) { + log(transition.router, transition.sequence, "detected abort."); + return new TransitionAborted(); + } + + function TransitionAborted(message) { + this.message = (message || "TransitionAborted"); + this.name = "TransitionAborted"; + } + + __exports__.Transition = Transition; + __exports__.logAbort = logAbort; + __exports__.TransitionAborted = TransitionAborted; + }); +enifed("router/utils", + ["exports"], + function(__exports__) { + "use strict"; + var slice = Array.prototype.slice; + + var _isArray; + if (!Array.isArray) { + _isArray = function (x) { + return Object.prototype.toString.call(x) === "[object Array]"; + }; + } else { + _isArray = Array.isArray; + } + + var isArray = _isArray; + __exports__.isArray = isArray; + function merge(hash, other) { + for (var prop in other) { + if (other.hasOwnProperty(prop)) { hash[prop] = other[prop]; } + } + } + + var oCreate = Object.create || function(proto) { + function F() {} + F.prototype = proto; + return new F(); + }; + __exports__.oCreate = oCreate; + /** + @private + + Extracts query params from the end of an array + **/ + function extractQueryParams(array) { + var len = (array && array.length), head, queryParams; + + if(len && len > 0 && array[len - 1] && array[len - 1].hasOwnProperty('queryParams')) { + queryParams = array[len - 1].queryParams; + head = slice.call(array, 0, len - 1); + return [head, queryParams]; + } else { + return [array, null]; + } + } + + __exports__.extractQueryParams = extractQueryParams;/** + @private + + Coerces query param properties and array elements into strings. + **/ + function coerceQueryParamsToString(queryParams) { + for (var key in queryParams) { + if (typeof queryParams[key] === 'number') { + queryParams[key] = '' + queryParams[key]; + } else if (isArray(queryParams[key])) { + for (var i = 0, l = queryParams[key].length; i < l; i++) { + queryParams[key][i] = '' + queryParams[key][i]; + } + } + } + } + /** + @private + */ + function log(router, sequence, msg) { + if (!router.log) { return; } + + if (arguments.length === 3) { + router.log("Transition #" + sequence + ": " + msg); + } else { + msg = sequence; + router.log(msg); + } + } + + __exports__.log = log;function bind(context, fn) { + var boundArgs = arguments; + return function(value) { + var args = slice.call(boundArgs, 2); + args.push(value); + return fn.apply(context, args); + }; + } + + __exports__.bind = bind;function isParam(object) { + return (typeof object === "string" || object instanceof String || typeof object === "number" || object instanceof Number); + } + + + function forEach(array, callback) { + for (var i=0, l=array.length; i=0; i--) { + var handlerInfo = handlerInfos[i], + handler = handlerInfo.handler; + + if (handler.events && handler.events[name]) { + if (handler.events[name].apply(handler, args) === true) { + eventWasHandled = true; + } else { + return; + } + } + } + + if (!eventWasHandled && !ignoreFailure) { + throw new Error("Nothing handled the event '" + name + "'."); + } + } + + __exports__.trigger = trigger;function getChangelist(oldObject, newObject) { + var key; + var results = { + all: {}, + changed: {}, + removed: {} + }; + + merge(results.all, newObject); + + var didChange = false; + coerceQueryParamsToString(oldObject); + coerceQueryParamsToString(newObject); + + // Calculate removals + for (key in oldObject) { + if (oldObject.hasOwnProperty(key)) { + if (!newObject.hasOwnProperty(key)) { + didChange = true; + results.removed[key] = oldObject[key]; + } + } + } + + // Calculate changes + for (key in newObject) { + if (newObject.hasOwnProperty(key)) { + if (isArray(oldObject[key]) && isArray(newObject[key])) { + if (oldObject[key].length !== newObject[key].length) { + results.changed[key] = newObject[key]; + didChange = true; + } else { + for (var i = 0, l = oldObject[key].length; i < l; i++) { + if (oldObject[key][i] !== newObject[key][i]) { + results.changed[key] = newObject[key]; + didChange = true; + } + } + } + } + else { + if (oldObject[key] !== newObject[key]) { + results.changed[key] = newObject[key]; + didChange = true; + } + } + } + } + + return didChange && results; + } + + __exports__.getChangelist = getChangelist;function promiseLabel(label) { + return 'Router: ' + label; + } + + __exports__.promiseLabel = promiseLabel;function subclass(parentConstructor, proto) { + function C(props) { + parentConstructor.call(this, props || {}); + } + C.prototype = oCreate(parentConstructor.prototype); + merge(C.prototype, proto); + return C; + } + + __exports__.subclass = subclass;function resolveHook(obj, hookName) { + if (!obj) { return; } + var underscored = "_" + hookName; + return obj[underscored] && underscored || + obj[hookName] && hookName; + } + + function callHook(obj, hookName) { + var args = slice.call(arguments, 2); + return applyHook(obj, hookName, args); + } + + function applyHook(obj, _hookName, args) { + var hookName = resolveHook(obj, _hookName); + if (hookName) { + return obj[hookName].apply(obj, args); + } + } + + __exports__.merge = merge; + __exports__.slice = slice; + __exports__.isParam = isParam; + __exports__.coerceQueryParamsToString = coerceQueryParamsToString; + __exports__.callHook = callHook; + __exports__.resolveHook = resolveHook; + __exports__.applyHook = applyHook; + }); +enifed("rsvp", + ["./rsvp/promise","./rsvp/events","./rsvp/node","./rsvp/all","./rsvp/all-settled","./rsvp/race","./rsvp/hash","./rsvp/hash-settled","./rsvp/rethrow","./rsvp/defer","./rsvp/config","./rsvp/map","./rsvp/resolve","./rsvp/reject","./rsvp/filter","./rsvp/asap","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var EventTarget = __dependency2__["default"]; + var denodeify = __dependency3__["default"]; + var all = __dependency4__["default"]; + var allSettled = __dependency5__["default"]; + var race = __dependency6__["default"]; + var hash = __dependency7__["default"]; + var hashSettled = __dependency8__["default"]; + var rethrow = __dependency9__["default"]; + var defer = __dependency10__["default"]; + var config = __dependency11__.config; + var configure = __dependency11__.configure; + var map = __dependency12__["default"]; + var resolve = __dependency13__["default"]; + var reject = __dependency14__["default"]; + var filter = __dependency15__["default"]; + var asap = __dependency16__["default"]; + + config.async = asap; // default async is asap; + var cast = resolve; + function async(callback, arg) { + config.async(callback, arg); + } + + function on() { + config.on.apply(config, arguments); + } + + function off() { + config.off.apply(config, arguments); + } + + // Set up instrumentation through `window.__PROMISE_INTRUMENTATION__` + if (typeof window !== 'undefined' && typeof window['__PROMISE_INSTRUMENTATION__'] === 'object') { + var callbacks = window['__PROMISE_INSTRUMENTATION__']; + configure('instrument', true); + for (var eventName in callbacks) { + if (callbacks.hasOwnProperty(eventName)) { + on(eventName, callbacks[eventName]); + } + } + } + + __exports__.cast = cast; + __exports__.Promise = Promise; + __exports__.EventTarget = EventTarget; + __exports__.all = all; + __exports__.allSettled = allSettled; + __exports__.race = race; + __exports__.hash = hash; + __exports__.hashSettled = hashSettled; + __exports__.rethrow = rethrow; + __exports__.defer = defer; + __exports__.denodeify = denodeify; + __exports__.configure = configure; + __exports__.on = on; + __exports__.off = off; + __exports__.resolve = resolve; + __exports__.reject = reject; + __exports__.async = async; + __exports__.map = map; + __exports__.filter = filter; + }); +enifed("rsvp.umd", + ["./rsvp"], + function(__dependency1__) { + "use strict"; + var Promise = __dependency1__.Promise; + var allSettled = __dependency1__.allSettled; + var hash = __dependency1__.hash; + var hashSettled = __dependency1__.hashSettled; + var denodeify = __dependency1__.denodeify; + var on = __dependency1__.on; + var off = __dependency1__.off; + var map = __dependency1__.map; + var filter = __dependency1__.filter; + var resolve = __dependency1__.resolve; + var reject = __dependency1__.reject; + var rethrow = __dependency1__.rethrow; + var all = __dependency1__.all; + var defer = __dependency1__.defer; + var EventTarget = __dependency1__.EventTarget; + var configure = __dependency1__.configure; + var race = __dependency1__.race; + var async = __dependency1__.async; + + var RSVP = { + 'race': race, + 'Promise': Promise, + 'allSettled': allSettled, + 'hash': hash, + 'hashSettled': hashSettled, + 'denodeify': denodeify, + 'on': on, + 'off': off, + 'map': map, + 'filter': filter, + 'resolve': resolve, + 'reject': reject, + 'all': all, + 'rethrow': rethrow, + 'defer': defer, + 'EventTarget': EventTarget, + 'configure': configure, + 'async': async + }; + + /* global define:true module:true window: true */ + if (typeof enifed === 'function' && enifed['amd']) { + enifed(function() { return RSVP; }); + } else if (typeof module !== 'undefined' && module['exports']) { + module['exports'] = RSVP; + } else if (typeof this !== 'undefined') { + this['RSVP'] = RSVP; + } + }); +enifed("rsvp/-internal", + ["./utils","./instrument","./config","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var objectOrFunction = __dependency1__.objectOrFunction; + var isFunction = __dependency1__.isFunction; + + var instrument = __dependency2__["default"]; + + var config = __dependency3__.config; + + function withOwnPromise() { + return new TypeError('A promises callback cannot return that same promise.'); + } + + function noop() {} + + var PENDING = void 0; + var FULFILLED = 1; + var REJECTED = 2; + + var GET_THEN_ERROR = new ErrorObject(); + + function getThen(promise) { + try { + return promise.then; + } catch(error) { + GET_THEN_ERROR.error = error; + return GET_THEN_ERROR; + } + } + + function tryThen(then, value, fulfillmentHandler, rejectionHandler) { + try { + then.call(value, fulfillmentHandler, rejectionHandler); + } catch(e) { + return e; + } + } + + function handleForeignThenable(promise, thenable, then) { + config.async(function(promise) { + var sealed = false; + var error = tryThen(then, thenable, function(value) { + if (sealed) { return; } + sealed = true; + if (thenable !== value) { + resolve(promise, value); + } else { + fulfill(promise, value); + } + }, function(reason) { + if (sealed) { return; } + sealed = true; + + reject(promise, reason); + }, 'Settle: ' + (promise._label || ' unknown promise')); + + if (!sealed && error) { + sealed = true; + reject(promise, error); + } + }, promise); + } + + function handleOwnThenable(promise, thenable) { + if (thenable._state === FULFILLED) { + fulfill(promise, thenable._result); + } else if (promise._state === REJECTED) { + reject(promise, thenable._result); + } else { + subscribe(thenable, undefined, function(value) { + if (thenable !== value) { + resolve(promise, value); + } else { + fulfill(promise, value); + } + }, function(reason) { + reject(promise, reason); + }); + } + } + + function handleMaybeThenable(promise, maybeThenable) { + if (maybeThenable.constructor === promise.constructor) { + handleOwnThenable(promise, maybeThenable); + } else { + var then = getThen(maybeThenable); + + if (then === GET_THEN_ERROR) { + reject(promise, GET_THEN_ERROR.error); + } else if (then === undefined) { + fulfill(promise, maybeThenable); + } else if (isFunction(then)) { + handleForeignThenable(promise, maybeThenable, then); + } else { + fulfill(promise, maybeThenable); + } + } + } + + function resolve(promise, value) { + if (promise === value) { + fulfill(promise, value); + } else if (objectOrFunction(value)) { + handleMaybeThenable(promise, value); + } else { + fulfill(promise, value); + } + } + + function publishRejection(promise) { + if (promise._onerror) { + promise._onerror(promise._result); + } + + publish(promise); + } + + function fulfill(promise, value) { + if (promise._state !== PENDING) { return; } + + promise._result = value; + promise._state = FULFILLED; + + if (promise._subscribers.length === 0) { + if (config.instrument) { + instrument('fulfilled', promise); + } + } else { + config.async(publish, promise); + } + } + + function reject(promise, reason) { + if (promise._state !== PENDING) { return; } + promise._state = REJECTED; + promise._result = reason; + + config.async(publishRejection, promise); + } + + function subscribe(parent, child, onFulfillment, onRejection) { + var subscribers = parent._subscribers; + var length = subscribers.length; + + parent._onerror = null; + + subscribers[length] = child; + subscribers[length + FULFILLED] = onFulfillment; + subscribers[length + REJECTED] = onRejection; + + if (length === 0 && parent._state) { + config.async(publish, parent); + } + } + + function publish(promise) { + var subscribers = promise._subscribers; + var settled = promise._state; + + if (config.instrument) { + instrument(settled === FULFILLED ? 'fulfilled' : 'rejected', promise); + } + + if (subscribers.length === 0) { return; } + + var child, callback, detail = promise._result; + + for (var i = 0; i < subscribers.length; i += 3) { + child = subscribers[i]; + callback = subscribers[i + settled]; + + if (child) { + invokeCallback(settled, child, callback, detail); + } else { + callback(detail); + } + } + + promise._subscribers.length = 0; + } + + function ErrorObject() { + this.error = null; + } + + var TRY_CATCH_ERROR = new ErrorObject(); + + function tryCatch(callback, detail) { + try { + return callback(detail); + } catch(e) { + TRY_CATCH_ERROR.error = e; + return TRY_CATCH_ERROR; + } + } + + function invokeCallback(settled, promise, callback, detail) { + var hasCallback = isFunction(callback), + value, error, succeeded, failed; + + if (hasCallback) { + value = tryCatch(callback, detail); + + if (value === TRY_CATCH_ERROR) { + failed = true; + error = value.error; + value = null; + } else { + succeeded = true; + } + + if (promise === value) { + reject(promise, withOwnPromise()); + return; + } + + } else { + value = detail; + succeeded = true; + } + + if (promise._state !== PENDING) { + // noop + } else if (hasCallback && succeeded) { + resolve(promise, value); + } else if (failed) { + reject(promise, error); + } else if (settled === FULFILLED) { + fulfill(promise, value); + } else if (settled === REJECTED) { + reject(promise, value); + } + } + + function initializePromise(promise, resolver) { + try { + resolver(function resolvePromise(value){ + resolve(promise, value); + }, function rejectPromise(reason) { + reject(promise, reason); + }); + } catch(e) { + reject(promise, e); + } + } + + __exports__.noop = noop; + __exports__.resolve = resolve; + __exports__.reject = reject; + __exports__.fulfill = fulfill; + __exports__.subscribe = subscribe; + __exports__.publish = publish; + __exports__.publishRejection = publishRejection; + __exports__.initializePromise = initializePromise; + __exports__.invokeCallback = invokeCallback; + __exports__.FULFILLED = FULFILLED; + __exports__.REJECTED = REJECTED; + __exports__.PENDING = PENDING; + }); +enifed("rsvp/all-settled", + ["./enumerator","./promise","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Enumerator = __dependency1__["default"]; + var makeSettledResult = __dependency1__.makeSettledResult; + var Promise = __dependency2__["default"]; + var o_create = __dependency3__.o_create; + + function AllSettled(Constructor, entries, label) { + this._superConstructor(Constructor, entries, false /* don't abort on reject */, label); + } + + AllSettled.prototype = o_create(Enumerator.prototype); + AllSettled.prototype._superConstructor = Enumerator; + AllSettled.prototype._makeResult = makeSettledResult; + AllSettled.prototype._validationError = function() { + return new Error('allSettled must be called with an array'); + }; + + /** + `RSVP.allSettled` is similar to `RSVP.all`, but instead of implementing + a fail-fast method, it waits until all the promises have returned and + shows you all the results. This is useful if you want to handle multiple + promises' failure states together as a set. + + Returns a promise that is fulfilled when all the given promises have been + settled. The return promise is fulfilled with an array of the states of + the promises passed into the `promises` array argument. + + Each state object will either indicate fulfillment or rejection, and + provide the corresponding value or reason. The states will take one of + the following formats: + + ```javascript + { state: 'fulfilled', value: value } + or + { state: 'rejected', reason: reason } + ``` + + Example: + + ```javascript + var promise1 = RSVP.Promise.resolve(1); + var promise2 = RSVP.Promise.reject(new Error('2')); + var promise3 = RSVP.Promise.reject(new Error('3')); + var promises = [ promise1, promise2, promise3 ]; + + RSVP.allSettled(promises).then(function(array){ + // array == [ + // { state: 'fulfilled', value: 1 }, + // { state: 'rejected', reason: Error }, + // { state: 'rejected', reason: Error } + // ] + // Note that for the second item, reason.message will be '2', and for the + // third item, reason.message will be '3'. + }, function(error) { + // Not run. (This block would only be called if allSettled had failed, + // for instance if passed an incorrect argument type.) + }); + ``` + + @method allSettled + @static + @for RSVP + @param {Array} promises + @param {String} label - optional string that describes the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled with an array of the settled + states of the constituent promises. + */ + + __exports__["default"] = function allSettled(entries, label) { + return new AllSettled(Promise, entries, label).promise; + } + }); +enifed("rsvp/all", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + This is a convenient alias for `RSVP.Promise.all`. + + @method all + @static + @for RSVP + @param {Array} array Array of promises. + @param {String} label An optional label. This is useful + for tooling. + */ + __exports__["default"] = function all(array, label) { + return Promise.all(array, label); + } + }); +enifed("rsvp/asap", + ["exports"], + function(__exports__) { + "use strict"; + var len = 0; + + __exports__["default"] = function asap(callback, arg) { + queue[len] = callback; + queue[len + 1] = arg; + len += 2; + if (len === 2) { + // If len is 1, that means that we need to schedule an async flush. + // If additional callbacks are queued before the queue is flushed, they + // will be processed by this flush that we are scheduling. + scheduleFlush(); + } + } + + var browserWindow = (typeof window !== 'undefined') ? window : undefined + var browserGlobal = browserWindow || {}; + var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver; + + // test for web worker but not in IE10 + var isWorker = typeof Uint8ClampedArray !== 'undefined' && + typeof importScripts !== 'undefined' && + typeof MessageChannel !== 'undefined'; + + // node + function useNextTick() { + return function() { + process.nextTick(flush); + }; + } + + // vertx + function useVertxTimer() { + return function() { + vertxNext(flush); + }; + } + + function useMutationObserver() { + var iterations = 0; + var observer = new BrowserMutationObserver(flush); + var node = document.createTextNode(''); + observer.observe(node, { characterData: true }); + + return function() { + node.data = (iterations = ++iterations % 2); + }; + } + + // web worker + function useMessageChannel() { + var channel = new MessageChannel(); + channel.port1.onmessage = flush; + return function () { + channel.port2.postMessage(0); + }; + } + + function useSetTimeout() { + return function() { + setTimeout(flush, 1); + }; + } + + var queue = new Array(1000); + function flush() { + for (var i = 0; i < len; i+=2) { + var callback = queue[i]; + var arg = queue[i+1]; + + callback(arg); + + queue[i] = undefined; + queue[i+1] = undefined; + } + + len = 0; + } + + function attemptVertex() { + try { + var vertx = eriuqer('vertx'); + var vertxNext = vertx.runOnLoop || vertx.runOnContext; + return useVertxTimer(); + } catch(e) { + return useSetTimeout(); + } + } + + var scheduleFlush; + // Decide what async method to use to triggering processing of queued callbacks: + if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') { + scheduleFlush = useNextTick(); + } else if (BrowserMutationObserver) { + scheduleFlush = useMutationObserver(); + } else if (isWorker) { + scheduleFlush = useMessageChannel(); + } else if (browserWindow === undefined && typeof eriuqer === 'function') { + scheduleFlush = attemptVertex(); + } else { + scheduleFlush = useSetTimeout(); + } + }); +enifed("rsvp/config", + ["./events","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var EventTarget = __dependency1__["default"]; + + var config = { + instrument: false + }; + + EventTarget.mixin(config); + + function configure(name, value) { + if (name === 'onerror') { + // handle for legacy users that expect the actual + // error to be passed to their function added via + // `RSVP.configure('onerror', someFunctionHere);` + config.on('error', value); + return; + } + + if (arguments.length === 2) { + config[name] = value; + } else { + return config[name]; + } + } + + __exports__.config = config; + __exports__.configure = configure; + }); +enifed("rsvp/defer", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + `RSVP.defer` returns an object similar to jQuery's `$.Deferred`. + `RSVP.defer` should be used when porting over code reliant on `$.Deferred`'s + interface. New code should use the `RSVP.Promise` constructor instead. + + The object returned from `RSVP.defer` is a plain object with three properties: + + * promise - an `RSVP.Promise`. + * reject - a function that causes the `promise` property on this object to + become rejected + * resolve - a function that causes the `promise` property on this object to + become fulfilled. + + Example: + + ```javascript + var deferred = RSVP.defer(); + + deferred.resolve("Success!"); + + defered.promise.then(function(value){ + // value here is "Success!" + }); + ``` + + @method defer + @static + @for RSVP + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Object} + */ + + __exports__["default"] = function defer(label) { + var deferred = { }; + + deferred['promise'] = new Promise(function(resolve, reject) { + deferred['resolve'] = resolve; + deferred['reject'] = reject; + }, label); + + return deferred; + } + }); +enifed("rsvp/enumerator", + ["./utils","./-internal","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var isArray = __dependency1__.isArray; + var isMaybeThenable = __dependency1__.isMaybeThenable; + + var noop = __dependency2__.noop; + var reject = __dependency2__.reject; + var fulfill = __dependency2__.fulfill; + var subscribe = __dependency2__.subscribe; + var FULFILLED = __dependency2__.FULFILLED; + var REJECTED = __dependency2__.REJECTED; + var PENDING = __dependency2__.PENDING; + + function makeSettledResult(state, position, value) { + if (state === FULFILLED) { + return { + state: 'fulfilled', + value: value + }; + } else { + return { + state: 'rejected', + reason: value + }; + } + } + + __exports__.makeSettledResult = makeSettledResult;function Enumerator(Constructor, input, abortOnReject, label) { + this._instanceConstructor = Constructor; + this.promise = new Constructor(noop, label); + this._abortOnReject = abortOnReject; + + if (this._validateInput(input)) { + this._input = input; + this.length = input.length; + this._remaining = input.length; + + this._init(); + + if (this.length === 0) { + fulfill(this.promise, this._result); + } else { + this.length = this.length || 0; + this._enumerate(); + if (this._remaining === 0) { + fulfill(this.promise, this._result); + } + } + } else { + reject(this.promise, this._validationError()); + } + } + + Enumerator.prototype._validateInput = function(input) { + return isArray(input); + }; + + Enumerator.prototype._validationError = function() { + return new Error('Array Methods must be provided an Array'); + }; + + Enumerator.prototype._init = function() { + this._result = new Array(this.length); + }; + + __exports__["default"] = Enumerator; + + Enumerator.prototype._enumerate = function() { + var length = this.length; + var promise = this.promise; + var input = this._input; + + for (var i = 0; promise._state === PENDING && i < length; i++) { + this._eachEntry(input[i], i); + } + }; + + Enumerator.prototype._eachEntry = function(entry, i) { + var c = this._instanceConstructor; + if (isMaybeThenable(entry)) { + if (entry.constructor === c && entry._state !== PENDING) { + entry._onerror = null; + this._settledAt(entry._state, i, entry._result); + } else { + this._willSettleAt(c.resolve(entry), i); + } + } else { + this._remaining--; + this._result[i] = this._makeResult(FULFILLED, i, entry); + } + }; + + Enumerator.prototype._settledAt = function(state, i, value) { + var promise = this.promise; + + if (promise._state === PENDING) { + this._remaining--; + + if (this._abortOnReject && state === REJECTED) { + reject(promise, value); + } else { + this._result[i] = this._makeResult(state, i, value); + } + } + + if (this._remaining === 0) { + fulfill(promise, this._result); + } + }; + + Enumerator.prototype._makeResult = function(state, i, value) { + return value; + }; + + Enumerator.prototype._willSettleAt = function(promise, i) { + var enumerator = this; + + subscribe(promise, undefined, function(value) { + enumerator._settledAt(FULFILLED, i, value); + }, function(reason) { + enumerator._settledAt(REJECTED, i, reason); + }); + }; + }); +enifed("rsvp/events", + ["exports"], + function(__exports__) { + "use strict"; + function indexOf(callbacks, callback) { + for (var i=0, l=callbacks.length; i 1; + }; + + RSVP.filter(promises, filterFn).then(function(result){ + // result is [ 2, 3 ] + }); + ``` + + If any of the `promises` given to `RSVP.filter` are rejected, the first promise + that is rejected will be given as an argument to the returned promise's + rejection handler. For example: + + ```javascript + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.reject(new Error('2')); + var promise3 = RSVP.reject(new Error('3')); + var promises = [ promise1, promise2, promise3 ]; + + var filterFn = function(item){ + return item > 1; + }; + + RSVP.filter(promises, filterFn).then(function(array){ + // Code here never runs because there are rejected promises! + }, function(reason) { + // reason.message === '2' + }); + ``` + + `RSVP.filter` will also wait for any promises returned from `filterFn`. + For instance, you may want to fetch a list of users then return a subset + of those users based on some asynchronous operation: + + ```javascript + + var alice = { name: 'alice' }; + var bob = { name: 'bob' }; + var users = [ alice, bob ]; + + var promises = users.map(function(user){ + return RSVP.resolve(user); + }); + + var filterFn = function(user){ + // Here, Alice has permissions to create a blog post, but Bob does not. + return getPrivilegesForUser(user).then(function(privs){ + return privs.can_create_blog_post === true; + }); + }; + RSVP.filter(promises, filterFn).then(function(users){ + // true, because the server told us only Alice can create a blog post. + users.length === 1; + // false, because Alice is the only user present in `users` + users[0] === bob; + }); + ``` + + @method filter + @static + @for RSVP + @param {Array} promises + @param {Function} filterFn - function to be called on each resolved value to + filter the final results. + @param {String} label optional string describing the promise. Useful for + tooling. + @return {Promise} + */ + __exports__["default"] = function filter(promises, filterFn, label) { + return Promise.all(promises, label).then(function(values) { + if (!isFunction(filterFn)) { + throw new TypeError("You must pass a function as filter's second argument."); + } + + var length = values.length; + var filtered = new Array(length); + + for (var i = 0; i < length; i++) { + filtered[i] = filterFn(values[i]); + } + + return Promise.all(filtered, label).then(function(filtered) { + var results = new Array(length); + var newLength = 0; + + for (var i = 0; i < length; i++) { + if (filtered[i]) { + results[newLength] = values[i]; + newLength++; + } + } + + results.length = newLength; + + return results; + }); + }); + } + }); +enifed("rsvp/hash-settled", + ["./promise","./enumerator","./promise-hash","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var makeSettledResult = __dependency2__.makeSettledResult; + var PromiseHash = __dependency3__["default"]; + var Enumerator = __dependency2__["default"]; + var o_create = __dependency4__.o_create; + + function HashSettled(Constructor, object, label) { + this._superConstructor(Constructor, object, false, label); + } + + HashSettled.prototype = o_create(PromiseHash.prototype); + HashSettled.prototype._superConstructor = Enumerator; + HashSettled.prototype._makeResult = makeSettledResult; + + HashSettled.prototype._validationError = function() { + return new Error('hashSettled must be called with an object'); + }; + + /** + `RSVP.hashSettled` is similar to `RSVP.allSettled`, but takes an object + instead of an array for its `promises` argument. + + Unlike `RSVP.all` or `RSVP.hash`, which implement a fail-fast method, + but like `RSVP.allSettled`, `hashSettled` waits until all the + constituent promises have returned and then shows you all the results + with their states and values/reasons. This is useful if you want to + handle multiple promises' failure states together as a set. + + Returns a promise that is fulfilled when all the given promises have been + settled, or rejected if the passed parameters are invalid. + + The returned promise is fulfilled with a hash that has the same key names as + the `promises` object argument. If any of the values in the object are not + promises, they will be copied over to the fulfilled object and marked with state + 'fulfilled'. + + Example: + + ```javascript + var promises = { + myPromise: RSVP.Promise.resolve(1), + yourPromise: RSVP.Promise.resolve(2), + theirPromise: RSVP.Promise.resolve(3), + notAPromise: 4 + }; + + RSVP.hashSettled(promises).then(function(hash){ + // hash here is an object that looks like: + // { + // myPromise: { state: 'fulfilled', value: 1 }, + // yourPromise: { state: 'fulfilled', value: 2 }, + // theirPromise: { state: 'fulfilled', value: 3 }, + // notAPromise: { state: 'fulfilled', value: 4 } + // } + }); + ``` + + If any of the `promises` given to `RSVP.hash` are rejected, the state will + be set to 'rejected' and the reason for rejection provided. + + Example: + + ```javascript + var promises = { + myPromise: RSVP.Promise.resolve(1), + rejectedPromise: RSVP.Promise.reject(new Error('rejection')), + anotherRejectedPromise: RSVP.Promise.reject(new Error('more rejection')), + }; + + RSVP.hashSettled(promises).then(function(hash){ + // hash here is an object that looks like: + // { + // myPromise: { state: 'fulfilled', value: 1 }, + // rejectedPromise: { state: 'rejected', reason: Error }, + // anotherRejectedPromise: { state: 'rejected', reason: Error }, + // } + // Note that for rejectedPromise, reason.message == 'rejection', + // and for anotherRejectedPromise, reason.message == 'more rejection'. + }); + ``` + + An important note: `RSVP.hashSettled` is intended for plain JavaScript objects that + are just a set of keys and values. `RSVP.hashSettled` will NOT preserve prototype + chains. + + Example: + + ```javascript + function MyConstructor(){ + this.example = RSVP.Promise.resolve('Example'); + } + + MyConstructor.prototype = { + protoProperty: RSVP.Promise.resolve('Proto Property') + }; + + var myObject = new MyConstructor(); + + RSVP.hashSettled(myObject).then(function(hash){ + // protoProperty will not be present, instead you will just have an + // object that looks like: + // { + // example: { state: 'fulfilled', value: 'Example' } + // } + // + // hash.hasOwnProperty('protoProperty'); // false + // 'undefined' === typeof hash.protoProperty + }); + ``` + + @method hashSettled + @for RSVP + @param {Object} promises + @param {String} label optional string that describes the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled when when all properties of `promises` + have been settled. + @static + */ + __exports__["default"] = function hashSettled(object, label) { + return new HashSettled(Promise, object, label).promise; + } + }); +enifed("rsvp/hash", + ["./promise","./promise-hash","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var PromiseHash = __dependency2__["default"]; + + /** + `RSVP.hash` is similar to `RSVP.all`, but takes an object instead of an array + for its `promises` argument. + + Returns a promise that is fulfilled when all the given promises have been + fulfilled, or rejected if any of them become rejected. The returned promise + is fulfilled with a hash that has the same key names as the `promises` object + argument. If any of the values in the object are not promises, they will + simply be copied over to the fulfilled object. + + Example: + + ```javascript + var promises = { + myPromise: RSVP.resolve(1), + yourPromise: RSVP.resolve(2), + theirPromise: RSVP.resolve(3), + notAPromise: 4 + }; + + RSVP.hash(promises).then(function(hash){ + // hash here is an object that looks like: + // { + // myPromise: 1, + // yourPromise: 2, + // theirPromise: 3, + // notAPromise: 4 + // } + }); + ```` + + If any of the `promises` given to `RSVP.hash` are rejected, the first promise + that is rejected will be given as the reason to the rejection handler. + + Example: + + ```javascript + var promises = { + myPromise: RSVP.resolve(1), + rejectedPromise: RSVP.reject(new Error('rejectedPromise')), + anotherRejectedPromise: RSVP.reject(new Error('anotherRejectedPromise')), + }; + + RSVP.hash(promises).then(function(hash){ + // Code here never runs because there are rejected promises! + }, function(reason) { + // reason.message === 'rejectedPromise' + }); + ``` + + An important note: `RSVP.hash` is intended for plain JavaScript objects that + are just a set of keys and values. `RSVP.hash` will NOT preserve prototype + chains. + + Example: + + ```javascript + function MyConstructor(){ + this.example = RSVP.resolve('Example'); + } + + MyConstructor.prototype = { + protoProperty: RSVP.resolve('Proto Property') + }; + + var myObject = new MyConstructor(); + + RSVP.hash(myObject).then(function(hash){ + // protoProperty will not be present, instead you will just have an + // object that looks like: + // { + // example: 'Example' + // } + // + // hash.hasOwnProperty('protoProperty'); // false + // 'undefined' === typeof hash.protoProperty + }); + ``` + + @method hash + @static + @for RSVP + @param {Object} promises + @param {String} label optional string that describes the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled when all properties of `promises` + have been fulfilled, or rejected if any of them become rejected. + */ + __exports__["default"] = function hash(object, label) { + return new PromiseHash(Promise, object, label).promise; + } + }); +enifed("rsvp/instrument", + ["./config","./utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var config = __dependency1__.config; + var now = __dependency2__.now; + + var queue = []; + + function scheduleFlush() { + setTimeout(function() { + var entry; + for (var i = 0; i < queue.length; i++) { + entry = queue[i]; + + var payload = entry.payload; + + payload.guid = payload.key + payload.id; + payload.childGuid = payload.key + payload.childId; + if (payload.error) { + payload.stack = payload.error.stack; + } + + config.trigger(entry.name, entry.payload); + } + queue.length = 0; + }, 50); + } + + __exports__["default"] = function instrument(eventName, promise, child) { + if (1 === queue.push({ + name: eventName, + payload: { + key: promise._guidKey, + id: promise._id, + eventName: eventName, + detail: promise._result, + childId: child && child._id, + label: promise._label, + timeStamp: now(), + error: config["instrument-with-stack"] ? new Error(promise._label) : null + }})) { + scheduleFlush(); + } + } + }); +enifed("rsvp/map", + ["./promise","./utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var isFunction = __dependency2__.isFunction; + + /** + `RSVP.map` is similar to JavaScript's native `map` method, except that it + waits for all promises to become fulfilled before running the `mapFn` on + each item in given to `promises`. `RSVP.map` returns a promise that will + become fulfilled with the result of running `mapFn` on the values the promises + become fulfilled with. + + For example: + + ```javascript + + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.resolve(2); + var promise3 = RSVP.resolve(3); + var promises = [ promise1, promise2, promise3 ]; + + var mapFn = function(item){ + return item + 1; + }; + + RSVP.map(promises, mapFn).then(function(result){ + // result is [ 2, 3, 4 ] + }); + ``` + + If any of the `promises` given to `RSVP.map` are rejected, the first promise + that is rejected will be given as an argument to the returned promise's + rejection handler. For example: + + ```javascript + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.reject(new Error('2')); + var promise3 = RSVP.reject(new Error('3')); + var promises = [ promise1, promise2, promise3 ]; + + var mapFn = function(item){ + return item + 1; + }; + + RSVP.map(promises, mapFn).then(function(array){ + // Code here never runs because there are rejected promises! + }, function(reason) { + // reason.message === '2' + }); + ``` + + `RSVP.map` will also wait if a promise is returned from `mapFn`. For example, + say you want to get all comments from a set of blog posts, but you need + the blog posts first because they contain a url to those comments. + + ```javscript + + var mapFn = function(blogPost){ + // getComments does some ajax and returns an RSVP.Promise that is fulfilled + // with some comments data + return getComments(blogPost.comments_url); + }; + + // getBlogPosts does some ajax and returns an RSVP.Promise that is fulfilled + // with some blog post data + RSVP.map(getBlogPosts(), mapFn).then(function(comments){ + // comments is the result of asking the server for the comments + // of all blog posts returned from getBlogPosts() + }); + ``` + + @method map + @static + @for RSVP + @param {Array} promises + @param {Function} mapFn function to be called on each fulfilled promise. + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled with the result of calling + `mapFn` on each fulfilled promise or value when they become fulfilled. + The promise will be rejected if any of the given `promises` become rejected. + @static + */ + __exports__["default"] = function map(promises, mapFn, label) { + return Promise.all(promises, label).then(function(values) { + if (!isFunction(mapFn)) { + throw new TypeError("You must pass a function as map's second argument."); + } + + var length = values.length; + var results = new Array(length); + + for (var i = 0; i < length; i++) { + results[i] = mapFn(values[i]); + } + + return Promise.all(results, label); + }); + } + }); +enifed("rsvp/node", + ["./promise","./-internal","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var noop = __dependency2__.noop; + var resolve = __dependency2__.resolve; + var reject = __dependency2__.reject; + var isArray = __dependency3__.isArray; + + function Result() { + this.value = undefined; + } + + var ERROR = new Result(); + var GET_THEN_ERROR = new Result(); + + function getThen(obj) { + try { + return obj.then; + } catch(error) { + ERROR.value= error; + return ERROR; + } + } + + + function tryApply(f, s, a) { + try { + f.apply(s, a); + } catch(error) { + ERROR.value = error; + return ERROR; + } + } + + function makeObject(_, argumentNames) { + var obj = {}; + var name; + var i; + var length = _.length; + var args = new Array(length); + + for (var x = 0; x < length; x++) { + args[x] = _[x]; + } + + for (i = 0; i < argumentNames.length; i++) { + name = argumentNames[i]; + obj[name] = args[i + 1]; + } + + return obj; + } + + function arrayResult(_) { + var length = _.length; + var args = new Array(length - 1); + + for (var i = 1; i < length; i++) { + args[i - 1] = _[i]; + } + + return args; + } + + function wrapThenable(then, promise) { + return { + then: function(onFulFillment, onRejection) { + return then.call(promise, onFulFillment, onRejection); + } + }; + } + + /** + `RSVP.denodeify` takes a 'node-style' function and returns a function that + will return an `RSVP.Promise`. You can use `denodeify` in Node.js or the + browser when you'd prefer to use promises over using callbacks. For example, + `denodeify` transforms the following: + + ```javascript + var fs = require('fs'); + + fs.readFile('myfile.txt', function(err, data){ + if (err) return handleError(err); + handleData(data); + }); + ``` + + into: + + ```javascript + var fs = require('fs'); + var readFile = RSVP.denodeify(fs.readFile); + + readFile('myfile.txt').then(handleData, handleError); + ``` + + If the node function has multiple success parameters, then `denodeify` + just returns the first one: + + ```javascript + var request = RSVP.denodeify(require('request')); + + request('http://example.com').then(function(res) { + // ... + }); + ``` + + However, if you need all success parameters, setting `denodeify`'s + second parameter to `true` causes it to return all success parameters + as an array: + + ```javascript + var request = RSVP.denodeify(require('request'), true); + + request('http://example.com').then(function(result) { + // result[0] -> res + // result[1] -> body + }); + ``` + + Or if you pass it an array with names it returns the parameters as a hash: + + ```javascript + var request = RSVP.denodeify(require('request'), ['res', 'body']); + + request('http://example.com').then(function(result) { + // result.res + // result.body + }); + ``` + + Sometimes you need to retain the `this`: + + ```javascript + var app = require('express')(); + var render = RSVP.denodeify(app.render.bind(app)); + ``` + + The denodified function inherits from the original function. It works in all + environments, except IE 10 and below. Consequently all properties of the original + function are available to you. However, any properties you change on the + denodeified function won't be changed on the original function. Example: + + ```javascript + var request = RSVP.denodeify(require('request')), + cookieJar = request.jar(); // <- Inheritance is used here + + request('http://example.com', {jar: cookieJar}).then(function(res) { + // cookieJar.cookies holds now the cookies returned by example.com + }); + ``` + + Using `denodeify` makes it easier to compose asynchronous operations instead + of using callbacks. For example, instead of: + + ```javascript + var fs = require('fs'); + + fs.readFile('myfile.txt', function(err, data){ + if (err) { ... } // Handle error + fs.writeFile('myfile2.txt', data, function(err){ + if (err) { ... } // Handle error + console.log('done') + }); + }); + ``` + + you can chain the operations together using `then` from the returned promise: + + ```javascript + var fs = require('fs'); + var readFile = RSVP.denodeify(fs.readFile); + var writeFile = RSVP.denodeify(fs.writeFile); + + readFile('myfile.txt').then(function(data){ + return writeFile('myfile2.txt', data); + }).then(function(){ + console.log('done') + }).catch(function(error){ + // Handle error + }); + ``` + + @method denodeify + @static + @for RSVP + @param {Function} nodeFunc a 'node-style' function that takes a callback as + its last argument. The callback expects an error to be passed as its first + argument (if an error occurred, otherwise null), and the value from the + operation as its second argument ('function(err, value){ }'). + @param {Boolean|Array} argumentNames An optional paramter that if set + to `true` causes the promise to fulfill with the callback's success arguments + as an array. This is useful if the node function has multiple success + paramters. If you set this paramter to an array with names, the promise will + fulfill with a hash with these names as keys and the success parameters as + values. + @return {Function} a function that wraps `nodeFunc` to return an + `RSVP.Promise` + @static + */ + __exports__["default"] = function denodeify(nodeFunc, options) { + var fn = function() { + var self = this; + var l = arguments.length; + var args = new Array(l + 1); + var arg; + var promiseInput = false; + + for (var i = 0; i < l; ++i) { + arg = arguments[i]; + + if (!promiseInput) { + // TODO: clean this up + promiseInput = needsPromiseInput(arg); + if (promiseInput === GET_THEN_ERROR) { + var p = new Promise(noop); + reject(p, GET_THEN_ERROR.value); + return p; + } else if (promiseInput && promiseInput !== true) { + arg = wrapThenable(promiseInput, arg); + } + } + args[i] = arg; + } + + var promise = new Promise(noop); + + args[l] = function(err, val) { + if (err) + reject(promise, err); + else if (options === undefined) + resolve(promise, val); + else if (options === true) + resolve(promise, arrayResult(arguments)); + else if (isArray(options)) + resolve(promise, makeObject(arguments, options)); + else + resolve(promise, val); + }; + + if (promiseInput) { + return handlePromiseInput(promise, args, nodeFunc, self); + } else { + return handleValueInput(promise, args, nodeFunc, self); + } + }; + + fn.__proto__ = nodeFunc; + + return fn; + } + + function handleValueInput(promise, args, nodeFunc, self) { + var result = tryApply(nodeFunc, self, args); + if (result === ERROR) { + reject(promise, result.value); + } + return promise; + } + + function handlePromiseInput(promise, args, nodeFunc, self){ + return Promise.all(args).then(function(args){ + var result = tryApply(nodeFunc, self, args); + if (result === ERROR) { + reject(promise, result.value); + } + return promise; + }); + } + + function needsPromiseInput(arg) { + if (arg && typeof arg === 'object') { + if (arg.constructor === Promise) { + return true; + } else { + return getThen(arg); + } + } else { + return false; + } + } + }); +enifed("rsvp/promise-hash", + ["./enumerator","./-internal","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Enumerator = __dependency1__["default"]; + var PENDING = __dependency2__.PENDING; + var o_create = __dependency3__.o_create; + + function PromiseHash(Constructor, object, label) { + this._superConstructor(Constructor, object, true, label); + } + + __exports__["default"] = PromiseHash; + + PromiseHash.prototype = o_create(Enumerator.prototype); + PromiseHash.prototype._superConstructor = Enumerator; + PromiseHash.prototype._init = function() { + this._result = {}; + }; + + PromiseHash.prototype._validateInput = function(input) { + return input && typeof input === 'object'; + }; + + PromiseHash.prototype._validationError = function() { + return new Error('Promise.hash must be called with an object'); + }; + + PromiseHash.prototype._enumerate = function() { + var promise = this.promise; + var input = this._input; + var results = []; + + for (var key in input) { + if (promise._state === PENDING && input.hasOwnProperty(key)) { + results.push({ + position: key, + entry: input[key] + }); + } + } + + var length = results.length; + this._remaining = length; + var result; + + for (var i = 0; promise._state === PENDING && i < length; i++) { + result = results[i]; + this._eachEntry(result.entry, result.position); + } + }; + }); +enifed("rsvp/promise", + ["./config","./instrument","./utils","./-internal","./promise/all","./promise/race","./promise/resolve","./promise/reject","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var config = __dependency1__.config; + var instrument = __dependency2__["default"]; + + var isFunction = __dependency3__.isFunction; + var now = __dependency3__.now; + + var noop = __dependency4__.noop; + var subscribe = __dependency4__.subscribe; + var initializePromise = __dependency4__.initializePromise; + var invokeCallback = __dependency4__.invokeCallback; + var FULFILLED = __dependency4__.FULFILLED; + var REJECTED = __dependency4__.REJECTED; + + var all = __dependency5__["default"]; + var race = __dependency6__["default"]; + var Resolve = __dependency7__["default"]; + var Reject = __dependency8__["default"]; + + var guidKey = 'rsvp_' + now() + '-'; + var counter = 0; + + function needsResolver() { + throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); + } + + function needsNew() { + throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); + } + __exports__["default"] = Promise; + /** + Promise objects represent the eventual result of an asynchronous operation. The + primary way of interacting with a promise is through its `then` method, which + registers callbacks to receive either a promise’s eventual value or the reason + why the promise cannot be fulfilled. + + Terminology + ----------- + + - `promise` is an object or function with a `then` method whose behavior conforms to this specification. + - `thenable` is an object or function that defines a `then` method. + - `value` is any legal JavaScript value (including undefined, a thenable, or a promise). + - `exception` is a value that is thrown using the throw statement. + - `reason` is a value that indicates why a promise was rejected. + - `settled` the final resting state of a promise, fulfilled or rejected. + + A promise can be in one of three states: pending, fulfilled, or rejected. + + Promises that are fulfilled have a fulfillment value and are in the fulfilled + state. Promises that are rejected have a rejection reason and are in the + rejected state. A fulfillment value is never a thenable. + + Promises can also be said to *resolve* a value. If this value is also a + promise, then the original promise's settled state will match the value's + settled state. So a promise that *resolves* a promise that rejects will + itself reject, and a promise that *resolves* a promise that fulfills will + itself fulfill. + + + Basic Usage: + ------------ + + ```js + var promise = new Promise(function(resolve, reject) { + // on success + resolve(value); + + // on failure + reject(reason); + }); + + promise.then(function(value) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Advanced Usage: + --------------- + + Promises shine when abstracting away asynchronous interactions such as + `XMLHttpRequest`s. + + ```js + function getJSON(url) { + return new Promise(function(resolve, reject){ + var xhr = new XMLHttpRequest(); + + xhr.open('GET', url); + xhr.onreadystatechange = handler; + xhr.responseType = 'json'; + xhr.setRequestHeader('Accept', 'application/json'); + xhr.send(); + + function handler() { + if (this.readyState === this.DONE) { + if (this.status === 200) { + resolve(this.response); + } else { + reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']')); + } + } + }; + }); + } + + getJSON('/posts.json').then(function(json) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Unlike callbacks, promises are great composable primitives. + + ```js + Promise.all([ + getJSON('/posts'), + getJSON('/comments') + ]).then(function(values){ + values[0] // => postsJSON + values[1] // => commentsJSON + + return values; + }); + ``` + + @class RSVP.Promise + @param {function} resolver + @param {String} label optional string for labeling the promise. + Useful for tooling. + @constructor + */ + function Promise(resolver, label) { + this._id = counter++; + this._label = label; + this._state = undefined; + this._result = undefined; + this._subscribers = []; + + if (config.instrument) { + instrument('created', this); + } + + if (noop !== resolver) { + if (!isFunction(resolver)) { + needsResolver(); + } + + if (!(this instanceof Promise)) { + needsNew(); + } + + initializePromise(this, resolver); + } + } + + Promise.cast = Resolve; // deprecated + Promise.all = all; + Promise.race = race; + Promise.resolve = Resolve; + Promise.reject = Reject; + + Promise.prototype = { + constructor: Promise, + + _guidKey: guidKey, + + _onerror: function (reason) { + config.trigger('error', reason); + }, + + /** + The primary way of interacting with a promise is through its `then` method, + which registers callbacks to receive either a promise's eventual value or the + reason why the promise cannot be fulfilled. + + ```js + findUser().then(function(user){ + // user is available + }, function(reason){ + // user is unavailable, and you are given the reason why + }); + ``` + + Chaining + -------- + + The return value of `then` is itself a promise. This second, 'downstream' + promise is resolved with the return value of the first promise's fulfillment + or rejection handler, or rejected if the handler throws an exception. + + ```js + findUser().then(function (user) { + return user.name; + }, function (reason) { + return 'default name'; + }).then(function (userName) { + // If `findUser` fulfilled, `userName` will be the user's name, otherwise it + // will be `'default name'` + }); + + findUser().then(function (user) { + throw new Error('Found user, but still unhappy'); + }, function (reason) { + throw new Error('`findUser` rejected and we're unhappy'); + }).then(function (value) { + // never reached + }, function (reason) { + // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'. + // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'. + }); + ``` + If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. + + ```js + findUser().then(function (user) { + throw new PedagogicalException('Upstream error'); + }).then(function (value) { + // never reached + }).then(function (value) { + // never reached + }, function (reason) { + // The `PedgagocialException` is propagated all the way down to here + }); + ``` + + Assimilation + ------------ + + Sometimes the value you want to propagate to a downstream promise can only be + retrieved asynchronously. This can be achieved by returning a promise in the + fulfillment or rejection handler. The downstream promise will then be pending + until the returned promise is settled. This is called *assimilation*. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // The user's comments are now available + }); + ``` + + If the assimliated promise rejects, then the downstream promise will also reject. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // If `findCommentsByAuthor` fulfills, we'll have the value here + }, function (reason) { + // If `findCommentsByAuthor` rejects, we'll have the reason here + }); + ``` + + Simple Example + -------------- + + Synchronous Example + + ```javascript + var result; + + try { + result = findResult(); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + findResult(function(result, err){ + if (err) { + // failure + } else { + // success + } + }); + ``` + + Promise Example; + + ```javascript + findResult().then(function(result){ + // success + }, function(reason){ + // failure + }); + ``` + + Advanced Example + -------------- + + Synchronous Example + + ```javascript + var author, books; + + try { + author = findAuthor(); + books = findBooksByAuthor(author); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + + function foundBooks(books) { + + } + + function failure(reason) { + + } + + findAuthor(function(author, err){ + if (err) { + failure(err); + // failure + } else { + try { + findBoooksByAuthor(author, function(books, err) { + if (err) { + failure(err); + } else { + try { + foundBooks(books); + } catch(reason) { + failure(reason); + } + } + }); + } catch(error) { + failure(err); + } + // success + } + }); + ``` + + Promise Example; + + ```javascript + findAuthor(). + then(findBooksByAuthor). + then(function(books){ + // found books + }).catch(function(reason){ + // something went wrong + }); + ``` + + @method then + @param {Function} onFulfilled + @param {Function} onRejected + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + then: function(onFulfillment, onRejection, label) { + var parent = this; + var state = parent._state; + + if (state === FULFILLED && !onFulfillment || state === REJECTED && !onRejection) { + if (config.instrument) { + instrument('chained', this, this); + } + return this; + } + + parent._onerror = null; + + var child = new this.constructor(noop, label); + var result = parent._result; + + if (config.instrument) { + instrument('chained', parent, child); + } + + if (state) { + var callback = arguments[state - 1]; + config.async(function(){ + invokeCallback(state, child, callback, result); + }); + } else { + subscribe(parent, child, onFulfillment, onRejection); + } + + return child; + }, + + /** + `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same + as the catch block of a try/catch statement. + + ```js + function findAuthor(){ + throw new Error('couldn't find that author'); + } + + // synchronous + try { + findAuthor(); + } catch(reason) { + // something went wrong + } + + // async with promises + findAuthor().catch(function(reason){ + // something went wrong + }); + ``` + + @method catch + @param {Function} onRejection + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + 'catch': function(onRejection, label) { + return this.then(null, onRejection, label); + }, + + /** + `finally` will be invoked regardless of the promise's fate just as native + try/catch/finally behaves + + Synchronous example: + + ```js + findAuthor() { + if (Math.random() > 0.5) { + throw new Error(); + } + return new Author(); + } + + try { + return findAuthor(); // succeed or fail + } catch(error) { + return findOtherAuther(); + } finally { + // always runs + // doesn't affect the return value + } + ``` + + Asynchronous example: + + ```js + findAuthor().catch(function(reason){ + return findOtherAuther(); + }).finally(function(){ + // author was either found, or not + }); + ``` + + @method finally + @param {Function} callback + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + 'finally': function(callback, label) { + var constructor = this.constructor; + + return this.then(function(value) { + return constructor.resolve(callback()).then(function(){ + return value; + }); + }, function(reason) { + return constructor.resolve(callback()).then(function(){ + throw reason; + }); + }, label); + } + }; + }); +enifed("rsvp/promise/all", + ["../enumerator","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Enumerator = __dependency1__["default"]; + + /** + `RSVP.Promise.all` accepts an array of promises, and returns a new promise which + is fulfilled with an array of fulfillment values for the passed promises, or + rejected with the reason of the first passed promise to be rejected. It casts all + elements of the passed iterable to promises as it runs this algorithm. + + Example: + + ```javascript + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.resolve(2); + var promise3 = RSVP.resolve(3); + var promises = [ promise1, promise2, promise3 ]; + + RSVP.Promise.all(promises).then(function(array){ + // The array here would be [ 1, 2, 3 ]; + }); + ``` + + If any of the `promises` given to `RSVP.all` are rejected, the first promise + that is rejected will be given as an argument to the returned promises's + rejection handler. For example: + + Example: + + ```javascript + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.reject(new Error("2")); + var promise3 = RSVP.reject(new Error("3")); + var promises = [ promise1, promise2, promise3 ]; + + RSVP.Promise.all(promises).then(function(array){ + // Code here never runs because there are rejected promises! + }, function(error) { + // error.message === "2" + }); + ``` + + @method all + @static + @param {Array} entries array of promises + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled when all `promises` have been + fulfilled, or rejected if any of them become rejected. + @static + */ + __exports__["default"] = function all(entries, label) { + return new Enumerator(this, entries, true /* abort on reject */, label).promise; + } + }); +enifed("rsvp/promise/race", + ["../utils","../-internal","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var isArray = __dependency1__.isArray; + + var noop = __dependency2__.noop; + var resolve = __dependency2__.resolve; + var reject = __dependency2__.reject; + var subscribe = __dependency2__.subscribe; + var PENDING = __dependency2__.PENDING; + + /** + `RSVP.Promise.race` returns a new promise which is settled in the same way as the + first passed promise to settle. + + Example: + + ```javascript + var promise1 = new RSVP.Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 1'); + }, 200); + }); + + var promise2 = new RSVP.Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 2'); + }, 100); + }); + + RSVP.Promise.race([promise1, promise2]).then(function(result){ + // result === 'promise 2' because it was resolved before promise1 + // was resolved. + }); + ``` + + `RSVP.Promise.race` is deterministic in that only the state of the first + settled promise matters. For example, even if other promises given to the + `promises` array argument are resolved, but the first settled promise has + become rejected before the other promises became fulfilled, the returned + promise will become rejected: + + ```javascript + var promise1 = new RSVP.Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 1'); + }, 200); + }); + + var promise2 = new RSVP.Promise(function(resolve, reject){ + setTimeout(function(){ + reject(new Error('promise 2')); + }, 100); + }); + + RSVP.Promise.race([promise1, promise2]).then(function(result){ + // Code here never runs + }, function(reason){ + // reason.message === 'promise 2' because promise 2 became rejected before + // promise 1 became fulfilled + }); + ``` + + An example real-world use case is implementing timeouts: + + ```javascript + RSVP.Promise.race([ajax('foo.json'), timeout(5000)]) + ``` + + @method race + @static + @param {Array} promises array of promises to observe + @param {String} label optional string for describing the promise returned. + Useful for tooling. + @return {Promise} a promise which settles in the same way as the first passed + promise to settle. + */ + __exports__["default"] = function race(entries, label) { + /*jshint validthis:true */ + var Constructor = this; + + var promise = new Constructor(noop, label); + + if (!isArray(entries)) { + reject(promise, new TypeError('You must pass an array to race.')); + return promise; + } + + var length = entries.length; + + function onFulfillment(value) { + resolve(promise, value); + } + + function onRejection(reason) { + reject(promise, reason); + } + + for (var i = 0; promise._state === PENDING && i < length; i++) { + subscribe(Constructor.resolve(entries[i]), undefined, onFulfillment, onRejection); + } + + return promise; + } + }); +enifed("rsvp/promise/reject", + ["../-internal","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var noop = __dependency1__.noop; + var _reject = __dependency1__.reject; + + /** + `RSVP.Promise.reject` returns a promise rejected with the passed `reason`. + It is shorthand for the following: + + ```javascript + var promise = new RSVP.Promise(function(resolve, reject){ + reject(new Error('WHOOPS')); + }); + + promise.then(function(value){ + // Code here doesn't run because the promise is rejected! + }, function(reason){ + // reason.message === 'WHOOPS' + }); + ``` + + Instead of writing the above, your code now simply becomes the following: + + ```javascript + var promise = RSVP.Promise.reject(new Error('WHOOPS')); + + promise.then(function(value){ + // Code here doesn't run because the promise is rejected! + }, function(reason){ + // reason.message === 'WHOOPS' + }); + ``` + + @method reject + @static + @param {Any} reason value that the returned promise will be rejected with. + @param {String} label optional string for identifying the returned promise. + Useful for tooling. + @return {Promise} a promise rejected with the given `reason`. + */ + __exports__["default"] = function reject(reason, label) { + /*jshint validthis:true */ + var Constructor = this; + var promise = new Constructor(noop, label); + _reject(promise, reason); + return promise; + } + }); +enifed("rsvp/promise/resolve", + ["../-internal","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var noop = __dependency1__.noop; + var _resolve = __dependency1__.resolve; + + /** + `RSVP.Promise.resolve` returns a promise that will become resolved with the + passed `value`. It is shorthand for the following: + + ```javascript + var promise = new RSVP.Promise(function(resolve, reject){ + resolve(1); + }); + + promise.then(function(value){ + // value === 1 + }); + ``` + + Instead of writing the above, your code now simply becomes the following: + + ```javascript + var promise = RSVP.Promise.resolve(1); + + promise.then(function(value){ + // value === 1 + }); + ``` + + @method resolve + @static + @param {Any} value value that the returned promise will be resolved with + @param {String} label optional string for identifying the returned promise. + Useful for tooling. + @return {Promise} a promise that will become fulfilled with the given + `value` + */ + __exports__["default"] = function resolve(object, label) { + /*jshint validthis:true */ + var Constructor = this; + + if (object && typeof object === 'object' && object.constructor === Constructor) { + return object; + } + + var promise = new Constructor(noop, label); + _resolve(promise, object); + return promise; + } + }); +enifed("rsvp/race", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + This is a convenient alias for `RSVP.Promise.race`. + + @method race + @static + @for RSVP + @param {Array} array Array of promises. + @param {String} label An optional label. This is useful + for tooling. + */ + __exports__["default"] = function race(array, label) { + return Promise.race(array, label); + } + }); +enifed("rsvp/reject", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + This is a convenient alias for `RSVP.Promise.reject`. + + @method reject + @static + @for RSVP + @param {Any} reason value that the returned promise will be rejected with. + @param {String} label optional string for identifying the returned promise. + Useful for tooling. + @return {Promise} a promise rejected with the given `reason`. + */ + __exports__["default"] = function reject(reason, label) { + return Promise.reject(reason, label); + } + }); +enifed("rsvp/resolve", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + This is a convenient alias for `RSVP.Promise.resolve`. + + @method resolve + @static + @for RSVP + @param {Any} value value that the returned promise will be resolved with + @param {String} label optional string for identifying the returned promise. + Useful for tooling. + @return {Promise} a promise that will become fulfilled with the given + `value` + */ + __exports__["default"] = function resolve(value, label) { + return Promise.resolve(value, label); + } + }); +enifed("rsvp/rethrow", + ["exports"], + function(__exports__) { + "use strict"; + /** + `RSVP.rethrow` will rethrow an error on the next turn of the JavaScript event + loop in order to aid debugging. + + Promises A+ specifies that any exceptions that occur with a promise must be + caught by the promises implementation and bubbled to the last handler. For + this reason, it is recommended that you always specify a second rejection + handler function to `then`. However, `RSVP.rethrow` will throw the exception + outside of the promise, so it bubbles up to your console if in the browser, + or domain/cause uncaught exception in Node. `rethrow` will also throw the + error again so the error can be handled by the promise per the spec. + + ```javascript + function throws(){ + throw new Error('Whoops!'); + } + + var promise = new RSVP.Promise(function(resolve, reject){ + throws(); + }); + + promise.catch(RSVP.rethrow).then(function(){ + // Code here doesn't run because the promise became rejected due to an + // error! + }, function (err){ + // handle the error here + }); + ``` + + The 'Whoops' error will be thrown on the next turn of the event loop + and you can watch for it in your console. You can also handle it using a + rejection handler given to `.then` or `.catch` on the returned promise. + + @method rethrow + @static + @for RSVP + @param {Error} reason reason the promise became rejected. + @throws Error + @static + */ + __exports__["default"] = function rethrow(reason) { + setTimeout(function() { + throw reason; + }); + throw reason; + } + }); +enifed("rsvp/utils", + ["exports"], + function(__exports__) { + "use strict"; + function objectOrFunction(x) { + return typeof x === 'function' || (typeof x === 'object' && x !== null); + } + + __exports__.objectOrFunction = objectOrFunction;function isFunction(x) { + return typeof x === 'function'; + } + + __exports__.isFunction = isFunction;function isMaybeThenable(x) { + return typeof x === 'object' && x !== null; + } + + __exports__.isMaybeThenable = isMaybeThenable;var _isArray; + if (!Array.isArray) { + _isArray = function (x) { + return Object.prototype.toString.call(x) === '[object Array]'; + }; + } else { + _isArray = Array.isArray; + } + + var isArray = _isArray; + __exports__.isArray = isArray; + // Date.now is not available in browsers < IE9 + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility + var now = Date.now || function() { return new Date().getTime(); }; + __exports__.now = now; + function F() { } + + var o_create = (Object.create || function (o) { + if (arguments.length > 1) { + throw new Error('Second argument not supported'); + } + if (typeof o !== 'object') { + throw new TypeError('Argument must be an object'); + } + F.prototype = o; + return new F(); + }); + __exports__.o_create = o_create; + }); +requireModule("ember"); + +})(); \ No newline at end of file diff --git a/bower_components/ember/package.json b/bower_components/ember/package.json new file mode 100644 index 0000000..e0fc470 --- /dev/null +++ b/bower_components/ember/package.json @@ -0,0 +1,11 @@ +{ + "name": "components-ember", + "version": "1.8.0", + "description": "Ember Application Framework", + "keywords": ["ember"], + "main": "./ember.js", + "dependencies": { + "jquery": ">=1.7.0 < 2.2.0", + "handlebars": ">= 1.0.0 < 2.0.0" + } +} diff --git a/bower_components/emblem/.bower.json b/bower_components/emblem/.bower.json new file mode 100644 index 0000000..38933ea --- /dev/null +++ b/bower_components/emblem/.bower.json @@ -0,0 +1,15 @@ +{ + "name": "emblem", + "homepage": "https://github.com/machty/emblem.js", + "version": "0.3.18", + "_release": "0.3.18", + "_resolution": { + "type": "version", + "tag": "0.3.18", + "commit": "35d92e03b398f195d6d8dbac6b673a884e08ccb6" + }, + "_source": "git://github.com/machty/emblem.js.git", + "_target": "~0.3.18", + "_originalSource": "emblem", + "_direct": true +} \ No newline at end of file diff --git a/bower_components/emblem/.gitignore b/bower_components/emblem/.gitignore new file mode 100644 index 0000000..20f0612 --- /dev/null +++ b/bower_components/emblem/.gitignore @@ -0,0 +1,17 @@ + +examples +node_modules +.sw[po] +.*.sw[po] + +lib/coffee-script/bootstrap +lib/coffee-script/*.tmp + +*gem + +.DS_Store + +tmp + +sauce_connect.log + diff --git a/bower_components/emblem/.travis.yml b/bower_components/emblem/.travis.yml new file mode 100644 index 0000000..2c3af6e --- /dev/null +++ b/bower_components/emblem/.travis.yml @@ -0,0 +1,10 @@ +language: node_js +node_js: +- '0.10' +before_script: grunt build +notifications: + email: false +env: + global: + - secure: Oqr6tnsBraZQno/K1iQ8027tKhHI7iAVXqI8tw32kdOkFZn7zcZ+Vg6yCd+CSat+OGqCmIPq7fLU/sl9fvCg491N7jTnuDIrhy+8SWL8KhiZxSGxWIErSQm0PXt8Qlhak4n1hKuZZQE/M8bOZ3zEh9xbDPxAwXRoPF2wyjRwnVU= + - secure: Kmp/VG4/SZqjta9M6W2e7K7s9yvo2bnVs8j7kak+HlfC+/HYlkUT41bTc0bXm0jd3ES6RpPHAl6nqibwEBqIjPh3e96dWcWhdqWDn5eQSbXL2fgkub0ykVOFe9vln4+2lb5aEkPva32Kjh5FNLGcVffsKCm57LTakgRAH1MW4+o= diff --git a/bower_components/emblem/Gruntfile.coffee b/bower_components/emblem/Gruntfile.coffee new file mode 100644 index 0000000..1d36284 --- /dev/null +++ b/bower_components/emblem/Gruntfile.coffee @@ -0,0 +1,138 @@ +module.exports = (grunt) -> + + require('matchdep').filterDev('grunt-*') + .filter((n) -> n != 'grunt-cli') + .forEach(grunt.loadNpmTasks); + + browsers = [ + browserName: "firefox", + version: "19", + platform: "XP" + , + browserName: "chrome", + platform: "XP" + , + browserName: "chrome", + platform: "linux" + , + browserName: "internet explorer", + platform: "WIN8", + version: "10" + , + browserName: "internet explorer", + platform: "VISTA", + version: "9" + , + browserName: "opera", + platform: "Windows 2008", + version: "12" + ] + + + # Project configuration. + grunt.initConfig + clean: ["tmp", "dist"] + + coffee: + lib: + files: [ + expand: true + cwd: 'src/' + src: ['**/*.coffee'] + dest: 'lib/' + ext: '.js' + ] + test: + files: + 'test/qunit_spec.js': 'test/qunit_spec.coffee' + options: + bare: true + + peg: + grammar: + src: "src/grammar.pegjs" + dest: "tmp/grammar.js" + options: + exportVar: 'Emblem.Parser' + + concat: + grammar: + src: "tmp/grammar.js" + dest: "lib/parser.js" + options: + banner: "var Emblem = require('./emblem');\n\n" + footer: "\n\nmodule.exports = Emblem.Parser;\n" + + browserify: + dist: + files: + 'dist/emblem.js': 'lib/emblem.js' + + uglify: + dist: + files: + 'dist/emblem.min.js': 'dist/emblem.js' + options: + beautify: + # Special unicode IN/DEDENT tokens get clobbered unless this is set. + ascii_only : true + + qunit: + all: ['test/**/*.html'] + + + simplemocha: + all: + src: ['test/*.js', 'test/resources/*.js'] + + options: + ui: 'qunit' + + connect: + server: + options: + base: "" + port: 9999 + middleware: (connect, options) -> + [ + require('connect-redirection')(), + ((req, res, next) -> + if (req.url == '/') + res.redirect('/test') + else + next() + ), + connect.static(options.base) + ] + watch: {} + + open: + dev: + path: 'http://127.0.0.1:9999/', + app: 'Google Chrome' + + 'saucelabs-qunit': + all: + options: + urls: ["http://127.0.0.1:9999/test/index.html"] + tunnelTimeout: 5 + build: process.env.TRAVIS_JOB_ID + concurrency: 3 + browsers: browsers + testname: "qunit tests" + tags: ["master"] + + grunt.registerTask 'dev', ['connect', 'open:dev', 'watch'] + + grunt.registerTask 'compileParser', 'Compile PegJS grammar file', + ['peg', 'concat:grammar'] + + grunt.registerTask 'build', ['clean', 'compileParser', 'coffee:lib', 'browserify', 'uglify'] + + grunt.registerTask 'test', ['coffee:test', 'qunit', 'simplemocha']#, 'saucelabs'] + + grunt.registerTask 'saucelabs', ['connect', 'saucelabs-qunit'] + + # Default task is to build and test. + grunt.registerTask 'default', ['build', 'test'] + diff --git a/bower_components/emblem/LICENSE b/bower_components/emblem/LICENSE new file mode 100644 index 0000000..1fe8e22 --- /dev/null +++ b/bower_components/emblem/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2013 Alex Matchneer + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/bower_components/emblem/README.md b/bower_components/emblem/README.md new file mode 100644 index 0000000..34c6435 --- /dev/null +++ b/bower_components/emblem/README.md @@ -0,0 +1,140 @@ +[![Build Status](https://travis-ci.org/machty/emblem.js.png)](https://travis-ci.org/machty/emblem.js) + +# Emblem.js + +Emblem.js is an indentation-based templating language that compiles +down to the [Handlebars.js](https://github.com/wycats/handlebars.js/) +runtime. It is therefore: + +1. Efficiently/easily precompilable +1. Compilable in the browser +1. Fully compatible with Ember.js's auto-updating templates (with + Ember-targeting/friendly syntax) + +Emblem's syntax most closely resembles that of the +[Slim templating language](http://slim-lang.com/). Please see the +[Emblem docs site](http://www.emblemjs.com) for a full explanation +of the syntax. + +Also check out the +[Embercast on Emblem.js](http://www.embercasts.com/episodes/2) + +## Handlebars Version Dependencies + +_Updated: July 2013_ + +In the push to Handlebars 1.0.0, some changes were made to the Handlebars +internals that broke Emblem, but Emblem's been fixed as of July 1, 2013. +Here are the versions you should be using: + +- Handlebars 1.0.0: Use Emblem >= 0.3.0 +- Handlebars <= 1.0.0.rc4: Use Emblem <= 0.2.9 + +## Query params + +_Updated: March 2014_ + +Handlebars >= 1.3.0 is required to use query params. + +Emblem uses the following syntax: +`= link-to 'index' (query-params foo="wat")` + +[Ember query params documentation](http://emberjs.com/guides/routing/query-params/) + +## Syntax Examples + +- [Read the syntax documentation](http://www.emblemjs.com/syntax). +- [Watch the Embercast](http://www.embercasts.com/episodes/2) +- [Check out this JSBin.](http://jsbin.com/ulegec/337/edit) +- Check out this [demo](http://emblem-test.herokuapp.com/) of + an [ember-rails](https://github.com/machty/ember-rails) site + with Emblem enabled. + +![Emblem.js Syntax](https://s3.amazonaws.com/machty/emblem-sample.png) + +## Using Emblem in your application + +You can use Emblem to compile either to vanilla Handlebars or Emberized +Handlebars. Let's assume you're compiling to Emberized Handlebars +for use with an Ember app. + +### Compiling in the Browser + +Follow the pattern in [this JSBin](http://jsbin.com/ulegec/337/edit): + +1. Include Handlebars +1. Include Emblem +1. Include Ember + +If you have a recent enough version of Ember, all the Emblem code you +put into ` + + + + + + + + + + + diff --git a/bower_components/emblem/test/index-1.2.html b/bower_components/emblem/test/index-1.2.html new file mode 100644 index 0000000..304adbc --- /dev/null +++ b/bower_components/emblem/test/index-1.2.html @@ -0,0 +1,30 @@ + + + + + QUnit Example + + + +
    + + + + + + + + + + + + diff --git a/bower_components/emblem/test/index-1.3.html b/bower_components/emblem/test/index-1.3.html new file mode 100644 index 0000000..20bfd4a --- /dev/null +++ b/bower_components/emblem/test/index-1.3.html @@ -0,0 +1,30 @@ + + + + + QUnit Example + + + +
    + + + + + + + + + + + + diff --git a/bower_components/emblem/test/index-full-ember.html b/bower_components/emblem/test/index-full-ember.html new file mode 100644 index 0000000..242a285 --- /dev/null +++ b/bower_components/emblem/test/index-full-ember.html @@ -0,0 +1,33 @@ + + + + + QUnit Example + + + +
    + + + + + + + + + + + + + + diff --git a/bower_components/emblem/test/index.html b/bower_components/emblem/test/index.html new file mode 100644 index 0000000..20bfd4a --- /dev/null +++ b/bower_components/emblem/test/index.html @@ -0,0 +1,30 @@ + + + + + QUnit Example + + + +
    + + + + + + + + + + + + diff --git a/bower_components/emblem/test/qunit_spec.coffee b/bower_components/emblem/test/qunit_spec.coffee new file mode 100644 index 0000000..6843510 --- /dev/null +++ b/bower_components/emblem/test/qunit_spec.coffee @@ -0,0 +1,2097 @@ + +# Test Setup: Set up an environment that'll work for both Node and Qunit tests. + +Ember = window?.Emblem || @Emblem || {} + +# These are needed for the full version ember to load properly +LoadedEmber = LoadedEmber || {} +Ember.Handlebars = LoadedEmber.Handlebars +Ember.warn = LoadedEmber.warn + +if Emblem? + # Qunit testing + _equal = equal + equals = equal = (a, b, msg) -> + # Allow exec with missing message params + _equal(a, b, msg || '') + + # In QUnit, we use module() instead of nonexistent suite() + window.suite = module +else + # Setup for Node package testing + Handlebars = require('handlebars') + EmberHandlebars = require('./resources/ember-template-compiler.js').EmberHandlebars + Emblem = require('../lib/emblem') + + # TODO: replace with real expect() + `expect = function() {};` + + {equal, equals, ok, throws} = require("assert") + +unless CompilerContext? + # Note that this doesn't have the same context separation as the rspec test. + # Both should be run for full acceptance of the two libary modes. + CompilerContext = + compile: (template, options) -> + Emblem.compile(Handlebars, template, options) + +supportsEachHelperDataKeywords = Handlebars.VERSION.slice(0, 3) >= 1.2 +supportsSubexpressions = Handlebars.VERSION.slice(0, 3) >= 1.3 + +precompileEmber = (emblem) -> + Emblem.precompile(EmberHandlebars, emblem).toString() + +shouldEmberPrecompileToHelper = (emblem, helper = 'bind-attr') -> + result = precompileEmber emblem + ok (result.match "helpers.#{helper}") or (result.match "helpers\\['#{helper}'\\]") + result + +shouldCompileToString = (string, hashOrArray, expected) -> + + if hashOrArray.constructor == String + shouldCompileToWithPartials(string, {}, false, hashOrArray, null, true) + else + shouldCompileToWithPartials(string, hashOrArray, false, expected, null, true) + +shouldCompileTo = (string, hashOrArray, expected, message) -> + if hashOrArray.constructor == String + shouldCompileToWithPartials(string, {}, false, hashOrArray, message) + else + shouldCompileToWithPartials(string, hashOrArray, false, expected, message) + +shouldCompileToWithPartials = (string, hashOrArray, partials, expected, message, strings) -> + options = null + if strings + options = {} + options.stringParams = true + + result = compileWithPartials(string, hashOrArray, partials, options) + equal(result, expected, "'" + result + "' should === '" + expected + "': " + message) + +compileWithPartials = (string, hashOrArray, partials, options = {}) -> + template = CompilerContext.compile(string, options) + if Object::toString.call(hashOrArray) == "[object Array]" + if helpers = hashOrArray[1] + for prop of Handlebars.helpers + helpers[prop] = helpers[prop] || Handlebars.helpers[prop] + + ary = [] + ary.push(hashOrArray[0]) + ary.push + helpers: hashOrArray[1] + partials: hashOrArray[2] + + else + ary = [hashOrArray] + + template.apply(this, ary) + +shouldThrow = (fn, exMessage) -> + caught = false + + try + fn() + catch e + caught = true + if exMessage + ok e.message.match(exMessage), "exception message matched" + + ok(caught, "an exception was thrown") + +Handlebars.registerHelper 'echo', (param) -> + "ECHO #{param}" + +suite "html one-liners" + +test "element only", -> + shouldCompileTo "p", "

    " + +test "with text", -> + shouldCompileTo "p Hello", "

    Hello

    " + +test "with more complex text", -> + shouldCompileTo "p Hello, how's it going with you today?", "

    Hello, how's it going with you today?

    " + +test "with trailing space", -> + shouldCompileTo "p Hello ", "

    Hello

    " + +suite "html multi-lines" + +test "two lines", -> + emblem = + """ + p This is + pretty cool. + """ + shouldCompileTo emblem, "

    This is pretty cool.

    " + +test "three lines", -> + emblem = + """ + p This is + pretty damn + cool. + """ + shouldCompileTo emblem, "

    This is pretty damn cool.

    " + +test "three lines w/ embedded html", -> + emblem = + """ + p This is + pretty damn + cool. + """ + shouldCompileTo emblem, "

    This is pretty damn cool.

    " + +test "indentation doesn't need to match starting inline content's", -> + emblem = + """ + span Hello, + How are you? + """ + shouldCompileTo emblem, "Hello, How are you?" + +test "indentation may vary between parent/child, must be consistent within inline-block", -> + emblem = + """ + div + span Hello, + How are you? + Excellent. + p asd + """ + shouldCompileTo emblem, "
    Hello, How are you? Excellent.

    asd

    " + + emblem = + """ + div + span Hello, + How are you? + Excellent. + """ + shouldThrow -> CompilerContext.compile emblem + +test "indentation may vary between parent/child, must be consistent within inline-block pt 2", -> + emblem = + """ + div + span Hello, + How are you? + Excellent. + """ + shouldCompileTo emblem, "
    Hello, How are you? Excellent.
    " + + +test "w/ mustaches", -> + emblem = + """ + div + span Hello, + {{foo}} are you? + Excellent. + """ + shouldCompileTo emblem, { foo: "YEAH" }, "
    Hello, YEAH are you? Excellent.
    " + +test "w/ block mustaches", -> + emblem = + ''' + p Hello, #{ sally | Hello}, + and {{sally: span Hello}}! + ''' + + shouldCompileTo emblem, + '

    Hello, Hello, and Hello!

    ' + + emblem = + ''' + p Hello, #{ sally: span: a Hello}! + ''' + shouldCompileTo emblem, + '

    Hello, Hello!

    ' + +test "with followup", -> + emblem = + """ + p This is + pretty cool. + p Hello. + """ + shouldCompileTo emblem, "

    This is pretty cool.

    Hello.

    " + +suite '#{} syntax' + +test 'acts like {{}}', -> + emblem = + ''' + span Yo #{foo}, I herd. + ''' + shouldCompileTo emblem, + { foo: '123' }, + "Yo <span>123</span>, I herd." + +test 'can start inline content', -> + emblem = + ''' + span #{foo}, I herd. + ''' + shouldCompileTo emblem, { foo: "dawg" }, "dawg, I herd." + +test 'can end inline content', -> + emblem = + ''' + span I herd #{foo} + ''' + shouldCompileTo emblem, { foo: "dawg" }, "I herd dawg" + +test "doesn't screw up parsing when # used in text nodes", -> + emblem = + ''' + span OMG #YOLO + ''' + shouldCompileTo emblem, "OMG #YOLO" + +test "# can be only thing on line", -> + emblem = + ''' + span # + ''' + shouldCompileTo emblem, "#" + +### TODO: this +test "can be escaped", -> + emblem = + ''' + span #\\{yes} + ''' + shouldCompileTo emblem, '#{yes}' +### + +runTextLineSuite = (ch) -> + + sct = (emblem, obj, expected) -> + unless expected? + expected = obj + obj = {} + + unless ch == '`' + expected = expected.replace /\n/g, "" + + # Replace tabs with optional trailing whitespace. + if ch == "'" + expected = expected.replace /\t/g, " " + else + expected = expected.replace /\t/g, "" + + emblem = emblem.replace /_/g, ch + + shouldCompileTo emblem, obj, expected + + + suite "text lines starting with '#{ch}'" + + test "basic", -> sct "_ What what", "What what\n\t" + test "with html", -> + sct '_ What what!', + 'What what!\n\t' + + test "multiline", -> + emblem = + """ + _ Blork + Snork + """ + sct emblem, "Blork\nSnork\n\t" + + test "triple multiline", -> + emblem = + """ + _ Blork + Snork + Bork + """ + sct emblem, "Blork\nSnork\nBork\n\t" + + test "quadruple multiline", -> + emblem = + """ + _ Blork + Snork + Bork + Fork + """ + sct emblem, "Blork\nSnork\nBork\nFork\n\t" + + test "multiline w/ trailing whitespace", -> + emblem = + """ + _ Blork + Snork + """ + sct emblem, "Blork \nSnork\n\t" + + test "secondline", -> + emblem = + """ + _ + Good + """ + sct emblem, "Good\n\t" + + test "secondline multiline", -> + emblem = + """ + _ + Good + Bork + """ + sct emblem, "Good\nBork\n\t" + + test "with a mustache", -> + emblem = + """ + _ Bork {{foo}}! + """ + sct emblem, + { foo: "YEAH" }, + 'Bork YEAH!\n\t' + + test "with mustaches", -> + emblem = + """ + _ Bork {{foo}} {{{bar}}}! + """ + sct emblem, + { foo: "YEAH", bar: "NO"}, + 'Bork YEAH NO!\n\t' + + test "indented, then in a row", -> + expect(0) + return "PENDING" + emblem = + """ + _ + Good + riddance2 + dude + gnar + foo + """ + sct emblem, "Good\n riddance2\n dude\n gnar\n foo\n\t" + + test "indented, then in a row, then indented", -> + expect(0) + return "PENDING" + emblem = + """ + _ + Good + riddance2 + dude + gnar + foo + far + faz + """ + sct emblem, "Good \n riddance2 \n dude \n gnar \n foo \n far \n faz \n\t" + + + + test "uneven indentation megatest", -> + expect(0) + return "PENDING" + emblem = + """ + _ + Good + riddance + dude + """ + sct emblem, "Good\n riddance\ndude\n\t" + + emblem = + """ + _ + Good + riddance3 + dude + """ + sct emblem, "Good\n riddance3\n dude\n\t" + + emblem = + """ + _ Good + riddance + dude + """ + sct emblem, "Good\nriddance\n dude\n\t" + + test "on each line", -> + emblem = + """ + pre + _ This + _ should + _ hopefully + _ work, and work well. + """ + sct emblem, '
    This\n\t  should\n\t hopefully\n\t   work, and work well.\n\t
    ' + + test "with blank", -> + emblem = + """ + pre + _ This + _ should + _ + _ hopefully + _ work, and work well. + """ + sct emblem, '
    This\n\t  should\n\t\n\t hopefully\n\t   work, and work well.\n\t
    ' + + +runTextLineSuite '|' +runTextLineSuite '`' +runTextLineSuite "'" + +suite "text line starting with angle bracket" + +test "can start with angle bracket html", -> + emblem = + """ + Hello + """ + shouldCompileTo emblem, "Hello" + +test "can start with angle bracket html and go to multiple lines", -> + emblem = + """ + Hello dude, + what's up? + """ + shouldCompileTo emblem, "Hello dude, what's up?" + +suite "preprocessor" + +test "it strips out preceding whitespace", -> + emblem = + """ + + p Hello + """ + shouldCompileTo emblem, "

    Hello

    " + +test "it handles preceding indentation", -> + emblem = " p Woot\n p Ha" + shouldCompileTo emblem, "

    Woot

    Ha

    " + +test "it handles preceding indentation and newlines", -> + emblem = "\n p Woot\n p Ha" + shouldCompileTo emblem, "

    Woot

    Ha

    " + +test "it handles preceding indentation and newlines pt 2", -> + emblem = " \n p Woot\n p Ha" + shouldCompileTo emblem, "

    Woot

    Ha

    " + +suite "comments" + +test "it strips out single line '/' comments", -> + emblem = + """ + p Hello + + / A comment + + h1 How are you? + """ + shouldCompileTo emblem, "

    Hello

    How are you?

    " + +test "it strips out multi-line '/' comments", -> + emblem = + """ + p Hello + + / A comment + that goes on to two lines + even three! + + h1 How are you? + """ + shouldCompileTo emblem, "

    Hello

    How are you?

    " + +test "it strips out multi-line '/' comments without text on the first line", -> + emblem = + """ + p Hello + + / + A comment + that goes on to two lines + even three! + + h1 How are you? + """ + shouldCompileTo emblem, "

    Hello

    How are you?

    " + + +test "mix and match with various indentation", -> + emblem = + """ + / A test + p Hello + + span + / This is gnarly + p Yessir nope. + + / Nothin but comments + so many comments. + + / + p Should not show up + """ + shouldCompileTo emblem, "

    Hello

    Yessir nope.

    " + +test "uneven indentation", -> + emblem = + """ + / nop + nope + nope + """ + shouldCompileTo emblem, "" + +test "uneven indentation 2", -> + emblem = + """ + / n + no + nop + nope + """ + shouldCompileTo emblem, "" + +test "uneven indentation 3", -> + emblem = + """ + / n + no + nop + nope + """ + shouldCompileTo emblem, "" + + +test "empty first line", -> + emblem = + """ + / + nop + nope + nope + no + """ + shouldCompileTo emblem, "" + +test "on same line as html content", -> + emblem = + """ + .container / This comment doesn't show up + .row / Nor does this + p Hello + """ + shouldCompileTo emblem, '

    Hello

    ' + +test "on same line as mustache content", -> + shouldCompileTo 'frank text="YES" text2="NO" / omg', 'WOO: YES NO' + +test "on same line as colon syntax", -> + emblem = + """ + ul: li: span / omg + | Hello + """ + shouldCompileTo emblem, '
    • Hello
    ' + +suite "indentation" + +# This test used to make sure the emblem code threw, but now we +# support multi-line syntax. +test "it doesn't throw when indenting after a line with inline content", -> + emblem = + """ + p Hello + p invalid + """ + shouldCompileTo emblem, "

    Hello p invalid

    " + +test "it throws on half dedent", -> + emblem = + """ + p + span This is ok + span This aint + """ + shouldThrow -> CompilerContext.compile emblem + +test "new indentation levels don't have to match parents'", -> + emblem = + """ + p + span + div + span yes + """ + shouldCompileTo emblem, "

    yes

    " + +suite "whitespace fussiness" + +test "spaces after html elements", -> + shouldCompileTo "p \n span asd", "

    asd

    " + shouldCompileTo "p \nspan \n\ndiv\nspan", "

    " + +test "spaces after mustaches", -> + shouldCompileTo "each foo \n p \n span", { foo: [1,2] }, "

    " + +suite "attribute shorthand" + +test "id shorthand", -> + shouldCompileTo "#woot", '
    ' + shouldCompileTo "span#woot", '' + +test "class shorthand", -> + shouldCompileTo ".woot", '
    ' + shouldCompileTo "span.woot", '' + shouldCompileTo "span.woot.loot", '' + +test "class can come first", -> + shouldCompileTo ".woot#hello", '
    ' + shouldCompileTo "span.woot#hello", '' + shouldCompileTo "span.woot.loot#hello", '' + shouldCompileTo "span.woot.loot#hello.boot", '' + +suite "full attributes - tags with content" + +test "class only", -> + shouldCompileTo 'p class="yes" Blork', '

    Blork

    ' +test "id only", -> + shouldCompileTo 'p id="yes" Hyeah', '

    Hyeah

    ' +test "class and id", -> + shouldCompileTo 'p id="yes" class="no" Blork', '

    Blork

    ' +test "class and id and embedded html one-liner", -> + shouldCompileTo 'p id="yes" class="no" One asd!', '

    One asd!

    ' + +test "bracketed attributes", -> + emblem = + """ + p [ + id="yes" + class="no" ] + | Bracketed Attributes FTW! + """ + shouldCompileTo emblem, '

    Bracketed Attributes FTW!

    ' +test "bracketed text", -> + emblem = + """ + p [ Bracketed text is cool ] + """ + shouldCompileTo emblem, '

    [ Bracketed text is cool ]

    ' + +test "bracketed text indented", -> + emblem = + """ + p + | [ Bracketed text is cool ] + """ + shouldCompileTo emblem, '

    [ Bracketed text is cool ]

    ' + +test "nesting", -> + emblem = + """ + p class="hello" data-foo="gnarly" + span Yes + """ + shouldCompileTo emblem, '

    Yes

    ' + +suite "full attributes - mixed quotes" + +test "single empty", -> + shouldCompileTo "p class=''", '

    ' +test "single full", -> + shouldCompileTo "p class='woot yeah'", '

    ' +test "mixed", -> + shouldCompileTo "p class='woot \"oof\" yeah'", '

    ' + +suite "full attributes - tags without content" + +test "empty", -> + shouldCompileTo 'p class=""', '

    ' +test "class only", -> + shouldCompileTo 'p class="yes"', '

    ' +test "id only", -> + shouldCompileTo 'p id="yes"', '

    ' +test "class and id", -> + shouldCompileTo 'p id="yes" class="no"', '

    ' + +suite "full attributes w/ mustaches" + +test "with mustache", -> + shouldCompileTo 'p class="foo {{yes}}"', {yes: "ALEX"}, '

    ' + shouldCompileTo 'p class="foo {{yes}}" Hello', {yes: "ALEX"}, '

    Hello

    ' + emblem = + """ + p class="foo {{yes}}" + | Hello + """ + shouldCompileTo emblem, {yes: "ALEX"}, '

    Hello

    ' + +test "with mustache calling helper", -> + shouldCompileTo 'p class="foo {{{echo "YES"}}}"', '

    ' + shouldCompileTo 'p class="foo #{echo "NO"} and {{{echo "YES"}}}" Hello', '

    Hello

    ' + emblem = + """ + p class="foo {{echo "BORF"}}" + | Hello + """ + shouldCompileTo emblem, '

    Hello

    ' + +suite "boolean attributes" + +test "static", -> + shouldCompileTo 'p borf=true', '

    ' + shouldCompileTo 'p borf=true Woot', '

    Woot

    ' + shouldCompileTo 'p borf=false', '

    ' + shouldCompileTo 'p borf=false Nork', '

    Nork

    ' + shouldCompileTo 'option selected=true Thingeroo', '' + +#test "dynamic", -> + ## TODO + #shouldCompileTo 'p borf=foo', { foo: true }, '

    ' + #shouldCompileTo 'p borf=foo', { foo: false }, '

    ' + #shouldCompileTo 'p borf=foo Yeah', { foo: true }, '

    Yeah

    ' + #shouldCompileTo 'p borf=foo Naww', { foo: false }, '

    Naww

    ' + #shouldCompileTo 'p borf=foo Naww', { foo: null }, '

    Naww

    ' + #shouldCompileTo 'p borf=foo Naww', { foo: undefined }, '

    Naww

    ' + #shouldCompileTo 'p borf=foo Naww', { foo: 0 }, '

    Naww

    ' + +suite "html nested" + +test "basic", -> + emblem = + """ + p + span Hello + strong Hi + div + p Hooray + """ + shouldCompileTo emblem, '

    HelloHi

    Hooray

    ' + +test "empty nest", -> + emblem = + """ + p + span + strong + i + """ + shouldCompileTo emblem, '

    ' + +test "empty nest w/ attribute shorthand", -> + emblem = + """ + p.woo + span#yes + strong.no.yes + i + """ + shouldCompileTo emblem, '

    ' + + +suite "simple mustache" + +test "various one-liners", -> + emblem = + """ + = foo + arf + p = foo + span.foo + p data-foo="yes" = goo + """ + shouldCompileTo emblem, + { foo: "ASD", arf: "QWE", goo: "WER" }, + 'ASDQWE

    ASD

    WER

    ' + + +test "double =='s un-escape", -> + emblem = + """ + == foo + foo + p == foo + """ + shouldCompileTo emblem, + { foo: '123' }, + '123<span>123</span>

    123

    ' + +test "nested combo syntax", -> + emblem = + """ + ul = each items + li = foo + """ + shouldCompileTo emblem, + { items: [ { foo: "YEAH"}, { foo: "BOI" } ] }, + '
    • YEAH
    • BOI
    ' + +suite "mustache helpers" + +Handlebars.registerHelper 'booltest', (options) -> + hash = options.hash + result = if hash.what == true + "true" + else if hash.what == false + "false" + else "neither" + result + +Handlebars.registerHelper 'hashtypetest', (options) -> + hash = options.hash + typeof hash.what + +Handlebars.registerHelper 'typetest', (num, options) -> + typeof num + +Handlebars.registerHelper 'frank', -> + options = arguments[arguments.length - 1] + "WOO: #{options.hash.text} #{options.hash.text2}" + +Handlebars.registerHelper 'sally', -> + options = arguments[arguments.length - 1] + params = Array::slice.call arguments, 0, -1 + param = params[0] || 'none' + if options.fn + content = options.fn @ + new Handlebars.SafeString """#{content}""" + else + content = param + new Handlebars.SafeString """#{content}""" + +test "basic", -> shouldCompileTo 'echo foo', {foo: "YES"}, 'ECHO YES' + +test "hashed parameters should work", -> + shouldCompileTo 'frank text="YES" text2="NO"', 'WOO: YES NO' + +Handlebars.registerHelper 'concatenator', -> + options = arguments[arguments.length - 1] + new Handlebars.SafeString ("'#{key}'='#{value}'" for key, value of options.hash).sort().join( " " ) + +test "negative integers should work", -> + shouldCompileTo 'concatenator positive=100 negative=-100', "'negative'='-100' 'positive'='100'" + +test "booleans", -> + shouldCompileToString 'typetest true', 'boolean' + shouldCompileToString 'typetest false', 'boolean' + shouldCompileTo 'booltest what=false', 'false' + shouldCompileTo 'booltest what=true', 'true' + shouldCompileTo 'booltest what="false"', 'neither' + shouldCompileTo 'booltest what="true"', 'neither' + +test "integers", -> + shouldCompileToString 'typetest 200', 'number' + shouldCompileTo 'hashtypetest what=1', 'number' + shouldCompileTo 'hashtypetest what=200', 'number' + +test "nesting", -> + emblem = + """ + sally + p Hello + """ + shouldCompileTo emblem, '

    Hello

    ' + +test "recursive nesting", -> + emblem = + """ + sally + sally + p Hello + """ + shouldCompileTo emblem, '

    Hello

    ' + +test "recursive nesting pt 2", -> + emblem = + """ + sally + sally thing + p Hello + """ + shouldCompileTo emblem, { thing: "woot" }, '

    Hello

    ' + +test "bracketed nested statement", -> + emblem = + """ + sally [ + 'foo' + something="false" ] + | Bracketed helper attrs! + """ + shouldCompileTo emblem, 'Bracketed helper attrs!' + +test "bracketed nested block", -> + emblem = + """ + sally [ + 'foo' + something="false" ] + p Bracketed helper attrs! + """ + shouldCompileTo emblem, '

    Bracketed helper attrs!

    ' + +Handlebars.registerHelper 'view', (param, a, b, c) -> + options = arguments[arguments.length - 1] + content = param + content = options.fn @ if options.fn + hashString = "" + for own k,v of options.hash + hashString += " #{k}=#{v}" + hashString = " nohash" unless hashString + + new Handlebars.SafeString """<#{param}#{hashString}>#{content}""" + +suite "capitalized line-starter" + +test "should invoke `view` helper by default", -> + emblem = + """ + SomeView + """ + shouldEmberPrecompileToHelper emblem, 'view' + #shouldCompileToString emblem, 'SomeView' + +test "should not invoke `view` helper for vanilla HB", -> + emblem = + """ + SomeView + """ + shouldCompileToString emblem, {SomeView: "ALEX"}, 'ALEX' + +test "should support block mode", -> + emblem = + """ + SomeView + p View content + """ + #shouldCompileToString emblem, '

    View content

    ' + shouldEmberPrecompileToHelper emblem, 'view' + +test "should not kick in if preceded by equal sign", -> + emblem = + """ + = SomeView + """ + shouldCompileTo emblem, { SomeView: 'erp' }, 'erp' + +test "should not kick in explicit {{mustache}}", -> + emblem = + """ + p Yeah {{SomeView}} + """ + shouldCompileTo emblem, { SomeView: 'erp' }, '

    Yeah erp

    ' + + +# TODO test overriding the default helper name (instead of always "view") + + +suite "bang syntax defaults to `unbound` helper syntax" + +Handlebars.registerHelper 'unbound', -> + options = arguments[arguments.length - 1] + params = Array::slice.call arguments, 0, -1 + stringedParams = params.join(' ') + content = if options.fn then options.fn @ else stringedParams + new Handlebars.SafeString """#{content}""" + +test "bang helper defaults to `unbound` invocation", -> + emblem = + """ + foo! Yar + = foo! + """ + shouldCompileToString emblem, 'foo Yarfoo' + +test "bang helper works with blocks", -> + emblem = + """ + hey! you suck + = foo! + """ + shouldCompileToString emblem, 'foo' + + +suite "question mark syntax defaults to `if` helper syntax" + +test "? helper defaults to `if` invocation", -> + emblem = + """ + foo? + p Yeah + """ + shouldCompileTo emblem, { foo: true }, '

    Yeah

    ' + + +test "else works", -> + emblem = + """ + foo? + p Yeah + else + p No + """ + shouldCompileTo emblem, { foo: false }, '

    No

    ' + + +test "compound", -> + emblem = + """ + p = foo? + | Hooray + else + | No + p = bar? + | Hooray + else + | No + """ + shouldCompileTo emblem, { foo: true, bar: false }, '

    Hooray

    No

    ' + + +test "compound", -> + emblem = + """ + p = foo? + bar + else + baz + """ + shouldCompileTo emblem, { foo: true, bar: "borf", baz: "narsty" }, '

    borf

    ' + +suite "conditionals" + +test "simple if statement", -> + emblem = + """ + if foo + | Foo + if bar + | Bar + """ + shouldCompileTo emblem, {foo: true, bar: false}, 'Foo' + +test "if else ", -> + emblem = + """ + if foo + | Foo + if bar + | Bar + else + | Woot + else + | WRONG + if bar + | WRONG + else + | Hooray + """ + shouldCompileTo emblem, {foo: true, bar: false}, 'FooWootHooray' + +test "else with preceding `=`", -> + emblem = + """ + = if foo + p Yeah + = else + p No + = if bar + p Yeah! + = else + p No! + =if bar + p Yeah! + =else + p No! + """ + shouldCompileTo emblem, {foo: true, bar: false}, '

    Yeah

    No!

    No!

    ' + + +test "unless", -> + emblem = + """ + unless bar + | Foo + unless foo + | Bar + else + | Woot + else + | WRONG + unless foo + | WRONG + else + | Hooray + """ + shouldCompileTo emblem, {foo: true, bar: false}, 'FooWootHooray' + +test "else followed by newline doesn't gobble else content", -> + emblem = + """ + if something + p something + else + + if nothing + p nothing + else + p not nothing + """ + shouldCompileTo emblem, {}, '

    not nothing

    ' + +suite "class shorthand and explicit declaration is coalesced" + +test "when literal class is used", -> + shouldCompileTo 'p.foo class="bar"', '

    ' + +test "when ember expression is used with variable", -> + shouldCompileTo 'p.foo class=bar', {bar: 'baz'}, '

    ' + +test "when ember expression is used with variable in braces", -> + result = shouldEmberPrecompileToHelper 'p.foo class={ bar }' + ok -1 != result.indexOf '\'class\': (":foo bar")' + +test "when ember expression is used with constant in braces", -> + result = shouldEmberPrecompileToHelper 'p.foo class={ :bar }' + ok -1 != result.indexOf '\'class\': (":foo :bar")' + +test "when ember expression is used with constant and variable in braces", -> + result = shouldEmberPrecompileToHelper 'p.foo class={ :bar bar }' + ok -1 != result.indexOf '\'class\': (":foo :bar bar")' + +test "when ember expression is used with bind-attr", -> + result = shouldEmberPrecompileToHelper 'p.foo{ bind-attr class="bar" }' + ok -1 != result.indexOf '\'class\': (":foo bar")' + +test "when ember expression is used with bind-attr and multiple attrs", -> + result = shouldEmberPrecompileToHelper 'p.foo{ bind-attr something=bind class="bar" }' + ok -1 != result.indexOf '\'class\': (":foo bar")' + +test "only with bind-attr helper", -> + result = shouldEmberPrecompileToHelper 'p.foo{ someHelper class="bar" }', 'someHelper' + ok -1 != result.indexOf '\'class\': ("bar")' + ok -1 != result.indexOf 'class=\\"foo\\"' + +bindAttrHelper = -> + options = arguments[arguments.length - 1] + params = Array::slice.call arguments, 0, -1 + bindingString = "" + for own k,v of options.hash + bindingString += " #{k} to #{v}" + bindingString = " narf" unless bindingString + param = params[0] || 'none' + "bind-attr#{bindingString}" + +Handlebars.registerHelper 'bind-attr', bindAttrHelper + +EmberHandlebars.registerHelper 'bind-attr', bindAttrHelper + +suite "bind-attr behavior for unquoted attribute values" + +test "basic", -> + emblem = 'p class=foo' + shouldCompileTo emblem, {foo:"YEAH"}, '

    ' + shouldEmberPrecompileToHelper emblem + +test "basic w/ underscore", -> + emblem = 'p class=foo_urns' + shouldCompileTo emblem, {foo_urns: "YEAH"}, '

    ' + shouldEmberPrecompileToHelper emblem + +test "subproperties", -> + emblem = 'p class=foo._death.woot' + shouldCompileTo emblem, {foo: { _death: { woot: "YEAH" } }}, '

    ' + shouldEmberPrecompileToHelper emblem + +test "multiple", -> + shouldCompileTo 'p class=foo id="yup" data-thinger=yeah Hooray', { foo: "FOO", yeah: "YEAH" }, + '

    Hooray

    ' + +test "class bind-attr special syntax", -> + emblem = 'p class=foo:bar:baz' + shouldEmberPrecompileToHelper emblem + shouldThrow (-> CompilerContext.compile emblem) + +test "class bind-attr braced syntax w/ underscores and dashes", -> + shouldEmberPrecompileToHelper 'p class={f-oo:bar :b_az}' + shouldEmberPrecompileToHelper 'p class={ f-oo:bar :b_az }' + shouldEmberPrecompileToHelper 'p class={ f-oo:bar :b_az } Hello' + emblem = + """ + .input-prepend class={ filterOn:input-append } + span.add-on + """ + shouldEmberPrecompileToHelper emblem + +test "exclamation modifier (vanilla)", -> + emblem = 'p class=foo!' + # exclamation is no-op in vanilla HB + shouldCompileTo emblem, {foo:"YEAH"}, '

    ' + +test "exclamation modifier (ember)", -> + emblem = 'p class=foo!' + + result = precompileEmber emblem + + ok result.match /p class/ + ok result.match /helpers\.unbound.*foo/ + + +suite "in-tag explicit mustache" + +Handlebars.registerHelper 'inTagHelper', (p) -> + return p; + +test "single", -> + shouldCompileTo 'p{inTagHelper foo}', {foo: "ALEX"}, '

    ' + +test "double", -> + shouldCompileTo 'p{inTagHelper foo}', {foo: "ALEX"}, '

    ' + +test "triple", -> + shouldCompileTo 'p{inTagHelper foo}', {foo: "ALEX"}, '

    ' + +Handlebars.registerHelper 'insertClass', (p) -> + return 'class="' + p + '"' + +test "with singlestache", -> + shouldCompileTo 'p{insertClass foo} Hello', {foo: "yar"}, '

    Hello

    ' + +test "singlestache can be used in text nodes", -> + shouldCompileTo 'p Hello {dork}', '

    Hello {dork}

    ' + +test "with doublestache", -> + shouldCompileTo 'p{{insertClass foo}} Hello', {foo: "yar"}, '

    Hello

    ' + +test "with triplestache", -> + shouldCompileTo 'p{{{insertClass foo}}} Hello', {foo: "yar"}, '

    Hello

    ' + +test "multiple", -> + shouldCompileTo 'p{{{insertClass foo}}}{{{insertClass boo}}} Hello', + {foo: "yar", boo: "nar"}, + '

    Hello

    ' + + +test "with nesting", -> + emblem = + """ + p{{bind-attr class="foo"}} + span Hello + """ + shouldCompileTo emblem, {foo: "yar"}, + '

    Hello

    ' + +suite "actions" + +Handlebars.registerHelper 'action', -> + options = arguments[arguments.length - 1] + params = Array::slice.call arguments, 0, -1 + + hashString = "" + paramsString = params.join('|') + + # TODO: bad because it relies on hash ordering? + # is this guaranteed? guess it doesn't rreeeeeally + # matter since order's not being tested. + for own k,v of options.hash + hashString += " #{k}=#{v}" + hashString = " nohash" unless hashString + "action #{paramsString}#{hashString}" + + +test "basic (click)", -> + emblem = + """ + button click="submitComment" Submit Comment + """ + shouldCompileToString emblem, '' + +test "basic (click) followed by attr", -> + emblem = + """ + button click="submitComment" class="foo" Submit Comment + """ + shouldCompileToString emblem, '' + + emblem = + """ + button click="submitComment 'omg'" class="foo" Submit Comment + """ + shouldCompileToString emblem, '' + +test "nested (mouseEnter)", -> + emblem = + """ + a mouseEnter='submitComment target="view"' + | Submit Comment + """ + shouldCompileToString emblem, 'Submit Comment' + +test "nested (mouseEnter, doublequoted)", -> + emblem = + """ + a mouseEnter="submitComment target='view'" + | Submit Comment + """ + shouldCompileToString emblem, 'Submit Comment' + +test "manual", -> + emblem = + """ + a{action submitComment target="view"} Submit Comment + """ + shouldCompileToString emblem, 'Submit Comment' + +test "manual nested", -> + emblem = + """ + a{action submitComment target="view"} + p Submit Comment + """ + shouldCompileToString emblem, '

    Submit Comment

    ' + +suite "haml style" + +test "basic", -> + emblem = + """ + %borf + """ + shouldCompileToString emblem, '' + +test "nested", -> + emblem = + """ + %borf + %sporf Hello + """ + shouldCompileToString emblem, 'Hello' + +test "capitalized", -> + emblem = + """ + %Alex alex + %Alex + %Woot + """ + shouldCompileToString emblem, 'alex' + +test "funky chars", -> + emblem = + """ + %borf:narf + %borf:narf Hello, {{foo}}. + %alex = foo + """ + shouldCompileToString emblem, + { foo: "Alex" }, + 'Hello, Alex.Alex' + +suite "line-based errors" + +test "line number is provided for pegjs error", -> + emblem = + """ + p Hello + p Hello {{narf} + """ + shouldThrow (-> CompilerContext.compile emblem), "line 2" + +# https://github.com/machty/emblem.js/issues/6 +test "single quote test", -> + emblem = + """ + button click='p' Frank + + / form s='d target="App"' + label I'm a label! + """ + shouldCompileToString emblem, '' + +test "double quote test", -> + emblem = + """ + button click="p" Frank + + / form s='d target="App"' + label I'm a label! + """ + shouldCompileToString emblem, '' + +test "no quote test", -> + emblem = + """ + button click=p Frank + + / form s='d target="App"' + label I'm a label! + """ + shouldCompileToString emblem, '' + +suite "mustache DOM attribute shorthand" + +test "tagName w/o space", -> + emblem = + """ + App.FunView%span + """ + result = precompileEmber emblem + ok result.match /helpers\.view/ + ok result.match /App\.FunView/ + ok result.match /tagName.*span/ + +test "tagName w/ space", -> + emblem = + """ + App.FunView %span + """ + result = precompileEmber emblem + ok result.match /helpers\.view/ + ok result.match /App\.FunView/ + ok result.match /tagName.*span/ + +test "tagName block", -> + emblem = + """ + view App.FunView%span + p Hello + """ + shouldCompileToString emblem, '

    Hello

    ' + +test "class w/ space (needs space)", -> + emblem = + """ + App.FunView .bork + """ + result = precompileEmber emblem + ok result.match /helpers\.view/ + ok result.match /App\.FunView/ + ok result.match /class.*bork/ + +test "multiple classes", -> + emblem = + """ + App.FunView .bork.snork + """ + result = precompileEmber emblem + ok result.match /helpers\.view/ + ok result.match /App\.FunView/ + ok result.match /class.*bork.*snork/ + +test "elementId", -> + emblem = + """ + App.FunView#ohno + """ + result = precompileEmber emblem + ok result.match /helpers\.view/ + ok result.match /App\.FunView/ + ok result.match /elementId.*ohno/ + +test "mixed w/ hash`", -> + emblem = + """ + App.FunView .bork.snork funbags="yeah" + """ + result = precompileEmber emblem + ok result.match /helpers\.view/ + ok result.match /App\.FunView/ + ok result.match /class.*bork.*snork/ + ok result.match /hash/ + ok result.match /funbags/ + ok result.match /yeah/ + +test "mixture of all`", -> + emblem = + """ + App.FunView%alex#hell.bork.snork funbags="yeah" + """ + result = precompileEmber emblem + ok result.match /helpers\.view/ + ok result.match /App\.FunView/ + ok result.match /tagName.*alex/ + ok result.match /elementId.*hell/ + ok result.match /class.*bork.*snork/ + ok result.match /hash/ + ok result.match /funbags/ + ok result.match /yeah/ + +suite "self-closing html tags" + +test "br", -> + emblem = + """ + br + """ + shouldCompileToString emblem, '
    ' + +test "br paragraph example", -> + emblem = + """ + p + | LOL! + br + | BORF! + """ + shouldCompileToString emblem, '

    LOL!
    BORF!

    ' + +test "input", -> + emblem = + """ + input type="text" + """ + shouldCompileToString emblem, '' + +suite "ember." + +test "should precompile with EmberHandlebars", -> + emblem = + """ + input type="text" + """ + result = Emblem.precompile(EmberHandlebars, 'p Hello').toString() + ok result.match '

    Hello

    ' + +suite "old school handlebars" + +test "array", -> + emblem = + ''' + goodbyes + | #{text}! + | cruel #{world}! + ''' + hash = {goodbyes: [{text: "goodbye"}, {text: "Goodbye"}, {text: "GOODBYE"}], world: "world"} + shouldCompileToString emblem, hash, "goodbye! Goodbye! GOODBYE! cruel world!" + + hash = {goodbyes: [], world: "world"} + shouldCompileToString emblem, hash, "cruel world!" + + +Handlebars.registerPartial('hbPartial', '{{name}}') + +test "calling handlebars partial", -> + emblem = + ''' + > hbPartial + | Hello #{> hbPartial} + ''' + shouldCompileToString emblem, + { id: 666, name: "Death" }, + 'DeathHello Death' + +Emblem.registerPartial(Handlebars, 'emblemPartial', 'a href="/people/{{id}}" = name') +Emblem.registerPartial(Handlebars, 'emblemPartialB', 'p Grr') +Emblem.registerPartial(Handlebars, 'emblemPartialC', 'p = a') + +test "calling emblem partial", -> + shouldCompileToString '> emblemPartial', { id: 666, name: "Death" }, 'Death' + +test "calling emblem partial with context", -> + shouldCompileToString '> emblemPartialC foo', { foo: { a: "YES" } }, '

    YES

    ' + +test "partials in mustaches", -> + emblem = + """ + | Hello, {{> emblemPartialC foo}}{{>emblemPartialB}}{{>emblemPartialB }} + """ + shouldCompileToString emblem, { foo: { a: "YES" } }, 'Hello,

    YES

    Grr

    Grr

    ' + +test "handlebars dot-separated paths with segment-literal notation", -> + emblem = + ''' + p = articles.[3] + ''' + shouldCompileTo emblem, { articles: ['zero', 'one', 'two', 'three']}, '

    three

    ' + +test "handlebars dot-separated paths with segment-literal notation, more nesting", -> + emblem = + ''' + p = articles.[3].[#comments].[0] + ''' + shouldCompileTo emblem, { articles: [{}, {}, {}, {'#comments': ['bazinga']}]}, '

    bazinga

    ' + +test "../path as inMustacheParam recognized correctly as pathIdNode instead of classShorthand", -> + Handlebars.registerHelper 'jumpToParent', (link) -> + new Handlebars.SafeString "Jump to parent top" + emblem = + ''' + each children + jumpToParent ../parentLink + ''' + shouldCompileTo emblem, {parentLink: '#anchor', children: [{}]}, 'Jump to parent top' + +test "block as #each", -> + emblem = + ''' + thangs + p Woot #{yeah} + ''' + shouldCompileToString emblem, { thangs: [{yeah: 123}, {yeah:456}] }, '

    Woot 123

    Woot 456

    ' + +if supportsEachHelperDataKeywords + + suite "each block helper keywords prefixed by @" + + test "#each with @index", -> + emblem = + ''' + thangs + p #{@index} Woot #{yeah} + ''' + shouldCompileToString emblem, { thangs: [{yeah: 123}, {yeah:456}] }, '

    0 Woot 123

    1 Woot 456

    ' + + test "#each with @key", -> + emblem = + ''' + each thangs + p #{@key}: #{this} + ''' + shouldCompileTo emblem, { thangs: {'@key': 123, 'works!':456} }, '

    @key: 123

    works!: 456

    ' + + test "#each with @key, @index", -> + emblem = + ''' + each thangs + p #{@index} #{@key}: #{this} + ''' + shouldCompileTo emblem, { thangs: {'@key': 123, 'works!':456} }, '

    0 @key: 123

    1 works!: 456

    ' + + test "#each with @key, @first", -> + emblem = + ''' + each thangs + if @first + p First item + else + p #{@key}: #{this} + ''' + shouldCompileTo emblem, { thangs: {'@key': 123, 'works!':456} }, '

    First item

    works!: 456

    ' + +### +test "partial in block", -> + emblem = + """ + ul = people + > link + """ + data = + people: [ + { "name": "Alan", "id": 1 } + { "name": "Yehuda", "id": 2 } + ] + shouldCompileToString emblem, data, '
      AlanYehuda
        ' +### + + +#suite "helper hash" + +#test "quoteless values get treated as bindings", -> + #emblem = + #""" + #view SomeView a=b + #| Yes + #""" + #shouldCompileToString emblem, 'Yes' + +#test "more complex", -> + #emblem = + #""" + #view SomeView a=b foo=thing.gnar + #""" + #shouldCompileToString emblem, 'SomeView' + +suite "inline block helper" + +test "text only", -> + emblem = + """ + view SomeView | Hello + """ + shouldCompileToString emblem, 'Hello' + +test "multiline", -> + emblem = + """ + view SomeView | Hello, + How are you? + Sup? + """ + shouldCompileToString emblem, 'Hello, How are you? Sup?' + +test "more complicated", -> + emblem = + """ + view SomeView borf="yes" | Hello, + How are you? + Sup? + """ + shouldCompileToString emblem, 'Hello, How are you? Sup?' + +suite "copy paste html" + +test "indented", -> + emblem = + """ +

        + This be some text + Basic HTML Sample Page +

        + """ + shouldCompileToString emblem, '

        This be some textBasic HTML Sample Page

        ' + +test "flatlina", -> + emblem = + """ +

        + This be some text + Basic HTML Sample Page +

        + """ + shouldCompileToString emblem, '

        This be some textBasic HTML Sample Page

        ' + +test "bigass", -> + expect(0) + return "PENDING" + emblem = + """ +
        +

        + We design and develop ambitious web and mobile applications, +

        +

        + A more official portfolio page is on its way, but in the meantime, + check out +

        +
        + """ + expected = '

        We design and develop ambitious web and mobile applications,

        A more official portfolio page is on its way, but in the meantime, check out

        ' + shouldCompileToString emblem, expected + +suite "`this` keyword" + +test "basic", -> + emblem = ''' + each foo + p = this + this + ''' + shouldCompileTo emblem, + { foo: [ "Alex", "Emily" ] }, + '

        Alex

        Alex

        Emily

        Emily' + +suite "colon separator" + +test "basic", -> + emblem = 'each foo: p Hello, #{this}' + shouldCompileTo emblem, + { foo: [ "Alex", "Emily", "Nicole" ] }, + '

        Hello, Alex

        Hello, Emily

        Hello, Nicole

        ' + +test "html stack", -> + emblem = '.container: .row: .span5: span Hello' + shouldCompileToString emblem, + '
        Hello
        ' + +test "epic", -> + emblem = ''' + .container: .row: .span5 + ul#list data-foo="yes": each foo: li + span: this + ''' + shouldCompileTo emblem, { foo: ["a","b"] }, + '
        • a
        • b
        ' + +test "html stack elements only", -> + emblem = 'p: span: div: p: foo' + shouldCompileToString emblem, { foo: "alex" }, + '

        alex

        ' + +test "mixed separators", -> + emblem = '.fun = each foo: %nork = this' + shouldCompileTo emblem, + { foo: [ "Alex", "Emily", "Nicole" ] }, + '
        AlexEmilyNicole
        ' + +test "mixed separators rewritten", -> + emblem = '.fun: each foo: %nork: this' + shouldCompileTo emblem, + { foo: [ "Alex", "Emily", "Nicole" ] }, + '
        AlexEmilyNicole
        ' + +test "with text terminator", -> + emblem = '.fun: view SomeView | Hello' + shouldCompileToString emblem, '
        Hello
        ' + +test "test from heartsentwined", -> + shouldCompileTo 'li data-foo=bar: a', { bar: "abc" }, '
      • ' + shouldCompileTo "li data-foo='bar': a", '
      • ' + +test "mixture of colon and indentation", -> + emblem = """ + li data-foo=bar: a + baz + """ + shouldCompileTo emblem, { bar: "abc", baz: "Hello" }, '
      • Hello
      • ' + +test "mixture of colon and indentation pt.2", -> + emblem = """ + ul + li data-foo=bar: a quux + li data-foo='bar': a quux + li data-foo=bar href='#': a quux + """ + result = precompileEmber emblem + ok(!result.match "a quux") + +suite "base indent / predent" + +test "predent", -> + emblem = " \n" + s = + """ + pre + ` This + ` should + ` hopefully + ` work, and work well. + + """ + emblem += s + shouldCompileToString emblem, '
        This\n  should\n hopefully\n   work, and work well.\n
        ' + +test "mixture", -> + emblem = " \n" + emblem += " p Hello\n" + emblem += " p\n" + emblem += " | Woot\n" + emblem += " span yes\n" + shouldCompileToString emblem, '

        Hello

        Woot

        yes' + +test "mixture w/o opening blank", -> + emblem = " p Hello\n" + emblem += " p\n" + emblem += " | Woot\n" + emblem += " span yes\n" + shouldCompileToString emblem, '

        Hello

        Woot

        yes' + +test "w/ blank lines", -> + emblem = " p Hello\n" + emblem += " p\n" + emblem += "\n" + emblem += " | Woot\n" + emblem += "\n" + emblem += " span yes\n" + shouldCompileToString emblem, '

        Hello

        Woot

        yes' + +test "w/ blank whitespaced lines", -> + emblem = " p Hello\n" + emblem += " p\n" + emblem += "\n" + emblem += " | Woot\n" + emblem += " \n" + emblem += " \n" + emblem += " \n" + emblem += "\n" + emblem += " span yes\n" + emblem += "\n" + emblem += " sally\n" + emblem += "\n" + emblem += " \n" + emblem += " | Woot\n" + shouldCompileToString emblem, '

        Hello

        Woot

        yesWoot' + +suite "EOL Whitespace" + +test "shouldn't be necessary to insert a space", -> + emblem = + """ + p Hello, + How are you? + p I'm fine, thank you. + """ + shouldCompileToString emblem, "

        Hello, How are you?

        I'm fine, thank you.

        " + + +suite "misc." + +test "end with indent", -> + expect(0) + return "PENDING" + emblem = + """ + div + p + span Butts + em fpokasd + iunw + paosdk + """ + shouldCompileToString emblem, '

        Buttsem fpokasdiunw paosdk

        ' + +test "capitalized view helper should not kick in if suffix modifiers present", -> + emblem = + """ + Foo! + """ + shouldCompileToString emblem, 'Foo' + +test "GH-26: no need for space before equal sign", -> + emblem = + """ + span= foo + """ + shouldCompileToString emblem, {foo: "YEAH"}, 'YEAH' + + emblem = + """ + span.foo= foo + """ + shouldCompileToString emblem, {foo: "YEAH"}, 'YEAH' + + emblem = + """ + span#hooray.foo= foo + """ + shouldCompileToString emblem, {foo: "YEAH"}, 'YEAH' + + emblem = + """ + #hooray= foo + """ + shouldCompileToString emblem, {foo: "YEAH"}, '
        YEAH
        ' + + emblem = + """ + .hooray= foo + """ + shouldCompileToString emblem, {foo: "YEAH"}, '
        YEAH
        ' + +test "numbers in shorthand", -> + shouldCompileToString '#4a', '
        ' + shouldCompileToString '.4a', '
        ' + shouldCompileToString '.4', '
        ' + shouldCompileToString '#4', '
        ' + shouldCompileToString '%4', '<4>' + shouldCompileToString '%4 ermagerd', '<4>ermagerd' + shouldCompileToString '%4#4.4 ermagerd', '<4 id="4" class="4">ermagerd' + +test "Emblem has a VERSION defined", -> + ok(Emblem.VERSION, "Emblem.VERSION should be defined") + +test "Windows line endings", -> + emblem = ".navigation\r\n p Hello\r\n#main\r\n | hi" + shouldCompileToString emblem, '
        hi
        ' + +test "backslash doesn't cause infinite loop", -> + emblem = + ''' + | \\ + ''' + shouldCompileTo emblem, "\\" + +test "backslash doesn't cause infinite loop with letter", -> + emblem = + ''' + | \\a + ''' + shouldCompileTo emblem, "\\a" + +test "self closing tag with forward slash", -> + emblem = + ''' + p/ + %bork/ + .omg/ + #hello.boo/ + p/ class="asdasd" + ''' + shouldCompileTo emblem, '

        ' + +test "tagnames and attributes with colons", -> + emblem = + ''' + %al:ex match:neer="snork" Hello! + ''' + shouldCompileTo emblem, 'Hello!' + +test "windows newlines", -> + emblem = "\r\n \r\n p Hello\r\n\r\n" + shouldCompileTo emblem, '

        Hello

        ' + +if supportsSubexpressions + + suite "subexpressions" + + Handlebars.registerHelper 'echo', (param) -> + "ECHO #{param}" + + Handlebars.registerHelper 'echofun', -> + options = Array.prototype.pop.call(arguments) + "FUN = #{options.hash.fun}" + + Handlebars.registerHelper 'hello', (param) -> + "hello" + + Handlebars.registerHelper 'equal', (x, y) -> + x == y + + test "arg-less helper", -> + emblem = 'p {{echo (hello)}}' + shouldCompileTo emblem, '

        ECHO hello

        ' + + emblem = '= echo (hello)' + shouldCompileTo emblem, 'ECHO hello' + + test "helper w args", -> + emblem = 'p {{echo (equal 1 1)}}' + shouldCompileTo emblem, '

        ECHO true

        ' + + emblem = '= echo (equal 1 1)' + shouldCompileTo emblem, 'ECHO true' + + test "supports much nesting", -> + emblem = 'p {{echo (equal (equal 1 1) true)}}' + shouldCompileTo emblem, '

        ECHO true

        ' + + emblem = '= echo (equal (equal 1 1) true)' + shouldCompileTo emblem, 'ECHO true' + + test "with hashes", -> + emblem = 'p {{echo (equal (equal 1 1) true fun="yes")}}' + shouldCompileTo emblem, '

        ECHO true

        ' + + emblem = '= echo (equal (equal 1 1) true fun="yes")' + shouldCompileTo emblem, 'ECHO true' + + test "as hashes", -> + emblem = 'p {{echofun fun=(equal 1 1)}}' + shouldCompileTo emblem, '

        FUN = true

        ' + + emblem = '= echofun fun=(equal 1 1)' + shouldCompileTo emblem, 'FUN = true' + + test "complex expression", -> + emblem = 'p {{echofun true (hello how="are" you=false) 1 not=true fun=(equal "ECHO hello" (echo (hello))) win="yes"}}' + shouldCompileTo emblem, '

        FUN = true

        ' + + emblem = '= echofun true (hello how="are" you=false) 1 not=true fun=(equal "ECHO hello" (echo (hello))) win="yes"' + shouldCompileTo emblem, 'FUN = true' diff --git a/bower_components/emblem/test/qunit_spec.js b/bower_components/emblem/test/qunit_spec.js new file mode 100644 index 0000000..4962393 --- /dev/null +++ b/bower_components/emblem/test/qunit_spec.js @@ -0,0 +1,1918 @@ +var CompilerContext, Ember, EmberHandlebars, Emblem, Handlebars, LoadedEmber, bindAttrHelper, compileWithPartials, equal, equals, ok, precompileEmber, runTextLineSuite, shouldCompileTo, shouldCompileToString, shouldCompileToWithPartials, shouldEmberPrecompileToHelper, shouldThrow, supportsEachHelperDataKeywords, supportsSubexpressions, throws, _equal, _ref, + __hasProp = {}.hasOwnProperty; + +Ember = (typeof window !== "undefined" && window !== null ? window.Emblem : void 0) || this.Emblem || {}; + +LoadedEmber = LoadedEmber || {}; + +Ember.Handlebars = LoadedEmber.Handlebars; + +Ember.warn = LoadedEmber.warn; + +if (typeof Emblem !== "undefined" && Emblem !== null) { + _equal = equal; + equals = equal = function(a, b, msg) { + return _equal(a, b, msg || ''); + }; + window.suite = module; +} else { + Handlebars = require('handlebars'); + EmberHandlebars = require('./resources/ember-template-compiler.js').EmberHandlebars; + Emblem = require('../lib/emblem'); + expect = function() {};; + _ref = require("assert"), equal = _ref.equal, equals = _ref.equals, ok = _ref.ok, throws = _ref.throws; +} + +if (typeof CompilerContext === "undefined" || CompilerContext === null) { + CompilerContext = { + compile: function(template, options) { + return Emblem.compile(Handlebars, template, options); + } + }; +} + +supportsEachHelperDataKeywords = Handlebars.VERSION.slice(0, 3) >= 1.2; + +supportsSubexpressions = Handlebars.VERSION.slice(0, 3) >= 1.3; + +precompileEmber = function(emblem) { + return Emblem.precompile(EmberHandlebars, emblem).toString(); +}; + +shouldEmberPrecompileToHelper = function(emblem, helper) { + var result; + if (helper == null) { + helper = 'bind-attr'; + } + result = precompileEmber(emblem); + ok((result.match("helpers." + helper)) || (result.match("helpers\\['" + helper + "'\\]"))); + return result; +}; + +shouldCompileToString = function(string, hashOrArray, expected) { + if (hashOrArray.constructor === String) { + return shouldCompileToWithPartials(string, {}, false, hashOrArray, null, true); + } else { + return shouldCompileToWithPartials(string, hashOrArray, false, expected, null, true); + } +}; + +shouldCompileTo = function(string, hashOrArray, expected, message) { + if (hashOrArray.constructor === String) { + return shouldCompileToWithPartials(string, {}, false, hashOrArray, message); + } else { + return shouldCompileToWithPartials(string, hashOrArray, false, expected, message); + } +}; + +shouldCompileToWithPartials = function(string, hashOrArray, partials, expected, message, strings) { + var options, result; + options = null; + if (strings) { + options = {}; + options.stringParams = true; + } + result = compileWithPartials(string, hashOrArray, partials, options); + return equal(result, expected, "'" + result + "' should === '" + expected + "': " + message); +}; + +compileWithPartials = function(string, hashOrArray, partials, options) { + var ary, helpers, prop, template; + if (options == null) { + options = {}; + } + template = CompilerContext.compile(string, options); + if (Object.prototype.toString.call(hashOrArray) === "[object Array]") { + if (helpers = hashOrArray[1]) { + for (prop in Handlebars.helpers) { + helpers[prop] = helpers[prop] || Handlebars.helpers[prop]; + } + } + ary = []; + ary.push(hashOrArray[0]); + ary.push({ + helpers: hashOrArray[1], + partials: hashOrArray[2] + }); + } else { + ary = [hashOrArray]; + } + return template.apply(this, ary); +}; + +shouldThrow = function(fn, exMessage) { + var caught, e; + caught = false; + try { + fn(); + } catch (_error) { + e = _error; + caught = true; + if (exMessage) { + ok(e.message.match(exMessage), "exception message matched"); + } + } + return ok(caught, "an exception was thrown"); +}; + +Handlebars.registerHelper('echo', function(param) { + return "ECHO " + param; +}); + +suite("html one-liners"); + +test("element only", function() { + return shouldCompileTo("p", "

        "); +}); + +test("with text", function() { + return shouldCompileTo("p Hello", "

        Hello

        "); +}); + +test("with more complex text", function() { + return shouldCompileTo("p Hello, how's it going with you today?", "

        Hello, how's it going with you today?

        "); +}); + +test("with trailing space", function() { + return shouldCompileTo("p Hello ", "

        Hello

        "); +}); + +suite("html multi-lines"); + +test("two lines", function() { + var emblem; + emblem = "p This is\n pretty cool."; + return shouldCompileTo(emblem, "

        This is pretty cool.

        "); +}); + +test("three lines", function() { + var emblem; + emblem = "p This is\n pretty damn\n cool."; + return shouldCompileTo(emblem, "

        This is pretty damn cool.

        "); +}); + +test("three lines w/ embedded html", function() { + var emblem; + emblem = "p This is\n pretty damn\n cool."; + return shouldCompileTo(emblem, "

        This is pretty damn cool.

        "); +}); + +test("indentation doesn't need to match starting inline content's", function() { + var emblem; + emblem = "span Hello,\n How are you?"; + return shouldCompileTo(emblem, "Hello, How are you?"); +}); + +test("indentation may vary between parent/child, must be consistent within inline-block", function() { + var emblem; + emblem = "div\n span Hello,\n How are you?\n Excellent.\n p asd"; + shouldCompileTo(emblem, "
        Hello, How are you? Excellent.

        asd

        "); + emblem = "div\n span Hello,\n How are you?\n Excellent."; + return shouldThrow(function() { + return CompilerContext.compile(emblem); + }); +}); + +test("indentation may vary between parent/child, must be consistent within inline-block pt 2", function() { + var emblem; + emblem = "div\n span Hello,\n How are you?\n Excellent."; + return shouldCompileTo(emblem, "
        Hello, How are you? Excellent.
        "); +}); + +test("w/ mustaches", function() { + var emblem; + emblem = "div\n span Hello,\n {{foo}} are you?\n Excellent."; + return shouldCompileTo(emblem, { + foo: "YEAH" + }, "
        Hello, YEAH are you? Excellent.
        "); +}); + +test("w/ block mustaches", function() { + var emblem; + emblem = 'p Hello, #{ sally | Hello},\n and {{sally: span Hello}}!'; + shouldCompileTo(emblem, '

        Hello, Hello, and Hello!

        '); + emblem = 'p Hello, #{ sally: span: a Hello}!'; + return shouldCompileTo(emblem, '

        Hello, Hello!

        '); +}); + +test("with followup", function() { + var emblem; + emblem = "p This is\n pretty cool.\np Hello."; + return shouldCompileTo(emblem, "

        This is pretty cool.

        Hello.

        "); +}); + +suite('#{} syntax'); + +test('acts like {{}}', function() { + var emblem; + emblem = 'span Yo #{foo}, I herd.'; + return shouldCompileTo(emblem, { + foo: '123' + }, "Yo <span>123</span>, I herd."); +}); + +test('can start inline content', function() { + var emblem; + emblem = 'span #{foo}, I herd.'; + return shouldCompileTo(emblem, { + foo: "dawg" + }, "dawg, I herd."); +}); + +test('can end inline content', function() { + var emblem; + emblem = 'span I herd #{foo}'; + return shouldCompileTo(emblem, { + foo: "dawg" + }, "I herd dawg"); +}); + +test("doesn't screw up parsing when # used in text nodes", function() { + var emblem; + emblem = 'span OMG #YOLO'; + return shouldCompileTo(emblem, "OMG #YOLO"); +}); + +test("# can be only thing on line", function() { + var emblem; + emblem = 'span #'; + return shouldCompileTo(emblem, "#"); +}); + +/* TODO: this +test "can be escaped", -> + emblem = + ''' + span #\\{yes} + ''' + shouldCompileTo emblem, '#{yes}' +*/ + + +runTextLineSuite = function(ch) { + var sct; + sct = function(emblem, obj, expected) { + if (expected == null) { + expected = obj; + obj = {}; + } + if (ch !== '`') { + expected = expected.replace(/\n/g, ""); + } + if (ch === "'") { + expected = expected.replace(/\t/g, " "); + } else { + expected = expected.replace(/\t/g, ""); + } + emblem = emblem.replace(/_/g, ch); + return shouldCompileTo(emblem, obj, expected); + }; + suite("text lines starting with '" + ch + "'"); + test("basic", function() { + return sct("_ What what", "What what\n\t"); + }); + test("with html", function() { + return sct('_ What what!', 'What what!\n\t'); + }); + test("multiline", function() { + var emblem; + emblem = "_ Blork\n Snork"; + return sct(emblem, "Blork\nSnork\n\t"); + }); + test("triple multiline", function() { + var emblem; + emblem = "_ Blork\n Snork\n Bork"; + return sct(emblem, "Blork\nSnork\nBork\n\t"); + }); + test("quadruple multiline", function() { + var emblem; + emblem = "_ Blork\n Snork\n Bork\n Fork"; + return sct(emblem, "Blork\nSnork\nBork\nFork\n\t"); + }); + test("multiline w/ trailing whitespace", function() { + var emblem; + emblem = "_ Blork \n Snork"; + return sct(emblem, "Blork \nSnork\n\t"); + }); + test("secondline", function() { + var emblem; + emblem = "_\n Good"; + return sct(emblem, "Good\n\t"); + }); + test("secondline multiline", function() { + var emblem; + emblem = "_ \n Good\n Bork"; + return sct(emblem, "Good\nBork\n\t"); + }); + test("with a mustache", function() { + var emblem; + emblem = "_ Bork {{foo}}!"; + return sct(emblem, { + foo: "YEAH" + }, 'Bork YEAH!\n\t'); + }); + test("with mustaches", function() { + var emblem; + emblem = "_ Bork {{foo}} {{{bar}}}!"; + return sct(emblem, { + foo: "YEAH", + bar: "NO" + }, 'Bork YEAH NO!\n\t'); + }); + test("indented, then in a row", function() { + var emblem; + expect(0); + return "PENDING"; + emblem = "_ \n Good\n riddance2\n dude\n gnar\n foo"; + return sct(emblem, "Good\n riddance2\n dude\n gnar\n foo\n\t"); + }); + test("indented, then in a row, then indented", function() { + var emblem; + expect(0); + return "PENDING"; + emblem = "_ \n Good\n riddance2\n dude\n gnar\n foo\n far\n faz"; + return sct(emblem, "Good \n riddance2 \n dude \n gnar \n foo \n far \n faz \n\t"); + }); + test("uneven indentation megatest", function() { + var emblem; + expect(0); + return "PENDING"; + emblem = "_ \n Good\n riddance\n dude"; + sct(emblem, "Good\n riddance\ndude\n\t"); + emblem = "_ \n Good\n riddance3\n dude"; + sct(emblem, "Good\n riddance3\n dude\n\t"); + emblem = "_ Good\n riddance\n dude"; + return sct(emblem, "Good\nriddance\n dude\n\t"); + }); + test("on each line", function() { + var emblem; + emblem = "pre\n _ This\n _ should\n _ hopefully\n _ work, and work well."; + return sct(emblem, '
        This\n\t  should\n\t hopefully\n\t   work, and work well.\n\t
        '); + }); + return test("with blank", function() { + var emblem; + emblem = "pre\n _ This\n _ should\n _\n _ hopefully\n _ work, and work well."; + return sct(emblem, '
        This\n\t  should\n\t\n\t hopefully\n\t   work, and work well.\n\t
        '); + }); +}; + +runTextLineSuite('|'); + +runTextLineSuite('`'); + +runTextLineSuite("'"); + +suite("text line starting with angle bracket"); + +test("can start with angle bracket html", function() { + var emblem; + emblem = "Hello"; + return shouldCompileTo(emblem, "Hello"); +}); + +test("can start with angle bracket html and go to multiple lines", function() { + var emblem; + emblem = "Hello dude, \n what's up?"; + return shouldCompileTo(emblem, "Hello dude, what's up?"); +}); + +suite("preprocessor"); + +test("it strips out preceding whitespace", function() { + var emblem; + emblem = "\np Hello"; + return shouldCompileTo(emblem, "

        Hello

        "); +}); + +test("it handles preceding indentation", function() { + var emblem; + emblem = " p Woot\n p Ha"; + return shouldCompileTo(emblem, "

        Woot

        Ha

        "); +}); + +test("it handles preceding indentation and newlines", function() { + var emblem; + emblem = "\n p Woot\n p Ha"; + return shouldCompileTo(emblem, "

        Woot

        Ha

        "); +}); + +test("it handles preceding indentation and newlines pt 2", function() { + var emblem; + emblem = " \n p Woot\n p Ha"; + return shouldCompileTo(emblem, "

        Woot

        Ha

        "); +}); + +suite("comments"); + +test("it strips out single line '/' comments", function() { + var emblem; + emblem = "p Hello\n\n/ A comment\n\nh1 How are you?"; + return shouldCompileTo(emblem, "

        Hello

        How are you?

        "); +}); + +test("it strips out multi-line '/' comments", function() { + var emblem; + emblem = "p Hello\n\n/ A comment\n that goes on to two lines\n even three!\n\nh1 How are you?"; + return shouldCompileTo(emblem, "

        Hello

        How are you?

        "); +}); + +test("it strips out multi-line '/' comments without text on the first line", function() { + var emblem; + emblem = "p Hello\n\n/ \n A comment\n that goes on to two lines\n even three!\n\nh1 How are you?"; + return shouldCompileTo(emblem, "

        Hello

        How are you?

        "); +}); + +test("mix and match with various indentation", function() { + var emblem; + emblem = "/ A test\np Hello\n\nspan\n / This is gnarly\n p Yessir nope.\n\n/ Nothin but comments\n so many comments.\n\n/\n p Should not show up"; + return shouldCompileTo(emblem, "

        Hello

        Yessir nope.

        "); +}); + +test("uneven indentation", function() { + var emblem; + emblem = "/ nop\n nope\n nope"; + return shouldCompileTo(emblem, ""); +}); + +test("uneven indentation 2", function() { + var emblem; + emblem = "/ n\n no\n nop\n nope"; + return shouldCompileTo(emblem, ""); +}); + +test("uneven indentation 3", function() { + var emblem; + emblem = "/ n\n no\n nop\n nope"; + return shouldCompileTo(emblem, ""); +}); + +test("empty first line", function() { + var emblem; + emblem = "/ \n nop\n nope\n nope\n no"; + return shouldCompileTo(emblem, ""); +}); + +test("on same line as html content", function() { + var emblem; + emblem = ".container / This comment doesn't show up\n .row / Nor does this\n p Hello"; + return shouldCompileTo(emblem, '

        Hello

        '); +}); + +test("on same line as mustache content", function() { + return shouldCompileTo('frank text="YES" text2="NO" / omg', 'WOO: YES NO'); +}); + +test("on same line as colon syntax", function() { + var emblem; + emblem = "ul: li: span / omg\n | Hello"; + return shouldCompileTo(emblem, '
        • Hello
        '); +}); + +suite("indentation"); + +test("it doesn't throw when indenting after a line with inline content", function() { + var emblem; + emblem = "p Hello\n p invalid"; + return shouldCompileTo(emblem, "

        Hello p invalid

        "); +}); + +test("it throws on half dedent", function() { + var emblem; + emblem = "p\n span This is ok\n span This aint"; + return shouldThrow(function() { + return CompilerContext.compile(emblem); + }); +}); + +test("new indentation levels don't have to match parents'", function() { + var emblem; + emblem = "p \n span\n div\n span yes"; + return shouldCompileTo(emblem, "

        yes

        "); +}); + +suite("whitespace fussiness"); + +test("spaces after html elements", function() { + shouldCompileTo("p \n span asd", "

        asd

        "); + return shouldCompileTo("p \nspan \n\ndiv\nspan", "

        "); +}); + +test("spaces after mustaches", function() { + return shouldCompileTo("each foo \n p \n span", { + foo: [1, 2] + }, "

        "); +}); + +suite("attribute shorthand"); + +test("id shorthand", function() { + shouldCompileTo("#woot", '
        '); + return shouldCompileTo("span#woot", ''); +}); + +test("class shorthand", function() { + shouldCompileTo(".woot", '
        '); + shouldCompileTo("span.woot", ''); + return shouldCompileTo("span.woot.loot", ''); +}); + +test("class can come first", function() { + shouldCompileTo(".woot#hello", '
        '); + shouldCompileTo("span.woot#hello", ''); + shouldCompileTo("span.woot.loot#hello", ''); + return shouldCompileTo("span.woot.loot#hello.boot", ''); +}); + +suite("full attributes - tags with content"); + +test("class only", function() { + return shouldCompileTo('p class="yes" Blork', '

        Blork

        '); +}); + +test("id only", function() { + return shouldCompileTo('p id="yes" Hyeah', '

        Hyeah

        '); +}); + +test("class and id", function() { + return shouldCompileTo('p id="yes" class="no" Blork', '

        Blork

        '); +}); + +test("class and id and embedded html one-liner", function() { + return shouldCompileTo('p id="yes" class="no" One asd!', '

        One asd!

        '); +}); + +test("bracketed attributes", function() { + var emblem; + emblem = "p [\n id=\"yes\"\n class=\"no\" ]\n | Bracketed Attributes FTW!"; + return shouldCompileTo(emblem, '

        Bracketed Attributes FTW!

        '); +}); + +test("bracketed text", function() { + var emblem; + emblem = "p [ Bracketed text is cool ]"; + return shouldCompileTo(emblem, '

        [ Bracketed text is cool ]

        '); +}); + +test("bracketed text indented", function() { + var emblem; + emblem = "p\n | [ Bracketed text is cool ]"; + return shouldCompileTo(emblem, '

        [ Bracketed text is cool ]

        '); +}); + +test("nesting", function() { + var emblem; + emblem = "p class=\"hello\" data-foo=\"gnarly\"\n span Yes"; + return shouldCompileTo(emblem, '

        Yes

        '); +}); + +suite("full attributes - mixed quotes"); + +test("single empty", function() { + return shouldCompileTo("p class=''", '

        '); +}); + +test("single full", function() { + return shouldCompileTo("p class='woot yeah'", '

        '); +}); + +test("mixed", function() { + return shouldCompileTo("p class='woot \"oof\" yeah'", '

        '); +}); + +suite("full attributes - tags without content"); + +test("empty", function() { + return shouldCompileTo('p class=""', '

        '); +}); + +test("class only", function() { + return shouldCompileTo('p class="yes"', '

        '); +}); + +test("id only", function() { + return shouldCompileTo('p id="yes"', '

        '); +}); + +test("class and id", function() { + return shouldCompileTo('p id="yes" class="no"', '

        '); +}); + +suite("full attributes w/ mustaches"); + +test("with mustache", function() { + var emblem; + shouldCompileTo('p class="foo {{yes}}"', { + yes: "ALEX" + }, '

        '); + shouldCompileTo('p class="foo {{yes}}" Hello', { + yes: "ALEX" + }, '

        Hello

        '); + emblem = "p class=\"foo {{yes}}\"\n | Hello"; + return shouldCompileTo(emblem, { + yes: "ALEX" + }, '

        Hello

        '); +}); + +test("with mustache calling helper", function() { + var emblem; + shouldCompileTo('p class="foo {{{echo "YES"}}}"', '

        '); + shouldCompileTo('p class="foo #{echo "NO"} and {{{echo "YES"}}}" Hello', '

        Hello

        '); + emblem = "p class=\"foo {{echo \"BORF\"}}\"\n | Hello"; + return shouldCompileTo(emblem, '

        Hello

        '); +}); + +suite("boolean attributes"); + +test("static", function() { + shouldCompileTo('p borf=true', '

        '); + shouldCompileTo('p borf=true Woot', '

        Woot

        '); + shouldCompileTo('p borf=false', '

        '); + shouldCompileTo('p borf=false Nork', '

        Nork

        '); + return shouldCompileTo('option selected=true Thingeroo', ''); +}); + +suite("html nested"); + +test("basic", function() { + var emblem; + emblem = "p\n span Hello\n strong Hi\ndiv\n p Hooray"; + return shouldCompileTo(emblem, '

        HelloHi

        Hooray

        '); +}); + +test("empty nest", function() { + var emblem; + emblem = "p\n span\n strong\n i"; + return shouldCompileTo(emblem, '

        '); +}); + +test("empty nest w/ attribute shorthand", function() { + var emblem; + emblem = "p.woo\n span#yes\n strong.no.yes\n i"; + return shouldCompileTo(emblem, '

        '); +}); + +suite("simple mustache"); + +test("various one-liners", function() { + var emblem; + emblem = "= foo\narf\np = foo\nspan.foo\np data-foo=\"yes\" = goo"; + return shouldCompileTo(emblem, { + foo: "ASD", + arf: "QWE", + goo: "WER" + }, 'ASDQWE

        ASD

        WER

        '); +}); + +test("double =='s un-escape", function() { + var emblem; + emblem = "== foo\nfoo\np == foo"; + return shouldCompileTo(emblem, { + foo: '123' + }, '123<span>123</span>

        123

        '); +}); + +test("nested combo syntax", function() { + var emblem; + emblem = "ul = each items\n li = foo"; + return shouldCompileTo(emblem, { + items: [ + { + foo: "YEAH" + }, { + foo: "BOI" + } + ] + }, '
        • YEAH
        • BOI
        '); +}); + +suite("mustache helpers"); + +Handlebars.registerHelper('booltest', function(options) { + var hash, result; + hash = options.hash; + result = hash.what === true ? "true" : hash.what === false ? "false" : "neither"; + return result; +}); + +Handlebars.registerHelper('hashtypetest', function(options) { + var hash; + hash = options.hash; + return typeof hash.what; +}); + +Handlebars.registerHelper('typetest', function(num, options) { + return typeof num; +}); + +Handlebars.registerHelper('frank', function() { + var options; + options = arguments[arguments.length - 1]; + return "WOO: " + options.hash.text + " " + options.hash.text2; +}); + +Handlebars.registerHelper('sally', function() { + var content, options, param, params; + options = arguments[arguments.length - 1]; + params = Array.prototype.slice.call(arguments, 0, -1); + param = params[0] || 'none'; + if (options.fn) { + content = options.fn(this); + return new Handlebars.SafeString("" + content + ""); + } else { + content = param; + return new Handlebars.SafeString("" + content + ""); + } +}); + +test("basic", function() { + return shouldCompileTo('echo foo', { + foo: "YES" + }, 'ECHO YES'); +}); + +test("hashed parameters should work", function() { + return shouldCompileTo('frank text="YES" text2="NO"', 'WOO: YES NO'); +}); + +Handlebars.registerHelper('concatenator', function() { + var key, options, value; + options = arguments[arguments.length - 1]; + return new Handlebars.SafeString(((function() { + var _ref1, _results; + _ref1 = options.hash; + _results = []; + for (key in _ref1) { + value = _ref1[key]; + _results.push("'" + key + "'='" + value + "'"); + } + return _results; + })()).sort().join(" ")); +}); + +test("negative integers should work", function() { + return shouldCompileTo('concatenator positive=100 negative=-100', "'negative'='-100' 'positive'='100'"); +}); + +test("booleans", function() { + shouldCompileToString('typetest true', 'boolean'); + shouldCompileToString('typetest false', 'boolean'); + shouldCompileTo('booltest what=false', 'false'); + shouldCompileTo('booltest what=true', 'true'); + shouldCompileTo('booltest what="false"', 'neither'); + return shouldCompileTo('booltest what="true"', 'neither'); +}); + +test("integers", function() { + shouldCompileToString('typetest 200', 'number'); + shouldCompileTo('hashtypetest what=1', 'number'); + return shouldCompileTo('hashtypetest what=200', 'number'); +}); + +test("nesting", function() { + var emblem; + emblem = "sally\n p Hello"; + return shouldCompileTo(emblem, '

        Hello

        '); +}); + +test("recursive nesting", function() { + var emblem; + emblem = "sally\n sally\n p Hello"; + return shouldCompileTo(emblem, '

        Hello

        '); +}); + +test("recursive nesting pt 2", function() { + var emblem; + emblem = "sally\n sally thing\n p Hello"; + return shouldCompileTo(emblem, { + thing: "woot" + }, '

        Hello

        '); +}); + +test("bracketed nested statement", function() { + var emblem; + emblem = "sally [\n 'foo'\n something=\"false\" ]\n | Bracketed helper attrs!"; + return shouldCompileTo(emblem, 'Bracketed helper attrs!'); +}); + +test("bracketed nested block", function() { + var emblem; + emblem = "sally [\n 'foo'\n something=\"false\" ]\n p Bracketed helper attrs!"; + return shouldCompileTo(emblem, '

        Bracketed helper attrs!

        '); +}); + +Handlebars.registerHelper('view', function(param, a, b, c) { + var content, hashString, k, options, v, _ref1; + options = arguments[arguments.length - 1]; + content = param; + if (options.fn) { + content = options.fn(this); + } + hashString = ""; + _ref1 = options.hash; + for (k in _ref1) { + if (!__hasProp.call(_ref1, k)) continue; + v = _ref1[k]; + hashString += " " + k + "=" + v; + } + if (!hashString) { + hashString = " nohash"; + } + return new Handlebars.SafeString("<" + param + hashString + ">" + content + ""); +}); + +suite("capitalized line-starter"); + +test("should invoke `view` helper by default", function() { + var emblem; + emblem = "SomeView"; + return shouldEmberPrecompileToHelper(emblem, 'view'); +}); + +test("should not invoke `view` helper for vanilla HB", function() { + var emblem; + emblem = "SomeView"; + return shouldCompileToString(emblem, { + SomeView: "ALEX" + }, 'ALEX'); +}); + +test("should support block mode", function() { + var emblem; + emblem = "SomeView\n p View content"; + return shouldEmberPrecompileToHelper(emblem, 'view'); +}); + +test("should not kick in if preceded by equal sign", function() { + var emblem; + emblem = "= SomeView"; + return shouldCompileTo(emblem, { + SomeView: 'erp' + }, 'erp'); +}); + +test("should not kick in explicit {{mustache}}", function() { + var emblem; + emblem = "p Yeah {{SomeView}}"; + return shouldCompileTo(emblem, { + SomeView: 'erp' + }, '

        Yeah erp

        '); +}); + +suite("bang syntax defaults to `unbound` helper syntax"); + +Handlebars.registerHelper('unbound', function() { + var content, options, params, stringedParams; + options = arguments[arguments.length - 1]; + params = Array.prototype.slice.call(arguments, 0, -1); + stringedParams = params.join(' '); + content = options.fn ? options.fn(this) : stringedParams; + return new Handlebars.SafeString("" + content + ""); +}); + +test("bang helper defaults to `unbound` invocation", function() { + var emblem; + emblem = "foo! Yar\n= foo!"; + return shouldCompileToString(emblem, 'foo Yarfoo'); +}); + +test("bang helper works with blocks", function() { + var emblem; + emblem = "hey! you suck\n = foo!"; + return shouldCompileToString(emblem, 'foo'); +}); + +suite("question mark syntax defaults to `if` helper syntax"); + +test("? helper defaults to `if` invocation", function() { + var emblem; + emblem = "foo?\n p Yeah"; + return shouldCompileTo(emblem, { + foo: true + }, '

        Yeah

        '); +}); + +test("else works", function() { + var emblem; + emblem = "foo?\n p Yeah\nelse\n p No"; + return shouldCompileTo(emblem, { + foo: false + }, '

        No

        '); +}); + +test("compound", function() { + var emblem; + emblem = "p = foo? \n | Hooray\nelse\n | No\np = bar? \n | Hooray\nelse\n | No"; + return shouldCompileTo(emblem, { + foo: true, + bar: false + }, '

        Hooray

        No

        '); +}); + +test("compound", function() { + var emblem; + emblem = "p = foo? \n bar\nelse\n baz"; + return shouldCompileTo(emblem, { + foo: true, + bar: "borf", + baz: "narsty" + }, '

        borf

        '); +}); + +suite("conditionals"); + +test("simple if statement", function() { + var emblem; + emblem = "if foo\n | Foo\nif bar\n | Bar"; + return shouldCompileTo(emblem, { + foo: true, + bar: false + }, 'Foo'); +}); + +test("if else ", function() { + var emblem; + emblem = "if foo\n | Foo\n if bar\n | Bar\n else\n | Woot\nelse\n | WRONG\nif bar\n | WRONG\nelse\n | Hooray"; + return shouldCompileTo(emblem, { + foo: true, + bar: false + }, 'FooWootHooray'); +}); + +test("else with preceding `=`", function() { + var emblem; + emblem = "= if foo\n p Yeah\n= else\n p No\n= if bar\n p Yeah!\n= else\n p No!\n=if bar\n p Yeah!\n=else\n p No!"; + return shouldCompileTo(emblem, { + foo: true, + bar: false + }, '

        Yeah

        No!

        No!

        '); +}); + +test("unless", function() { + var emblem; + emblem = "unless bar\n | Foo\n unless foo\n | Bar\n else\n | Woot\nelse\n | WRONG\nunless foo\n | WRONG\nelse\n | Hooray"; + return shouldCompileTo(emblem, { + foo: true, + bar: false + }, 'FooWootHooray'); +}); + +test("else followed by newline doesn't gobble else content", function() { + var emblem; + emblem = "if something\n p something\nelse\n\n if nothing\n p nothing\n else\n p not nothing"; + return shouldCompileTo(emblem, {}, '

        not nothing

        '); +}); + +suite("class shorthand and explicit declaration is coalesced"); + +test("when literal class is used", function() { + return shouldCompileTo('p.foo class="bar"', '

        '); +}); + +test("when ember expression is used with variable", function() { + return shouldCompileTo('p.foo class=bar', { + bar: 'baz' + }, '

        '); +}); + +test("when ember expression is used with variable in braces", function() { + var result; + result = shouldEmberPrecompileToHelper('p.foo class={ bar }'); + return ok(-1 !== result.indexOf('\'class\': (":foo bar")')); +}); + +test("when ember expression is used with constant in braces", function() { + var result; + result = shouldEmberPrecompileToHelper('p.foo class={ :bar }'); + return ok(-1 !== result.indexOf('\'class\': (":foo :bar")')); +}); + +test("when ember expression is used with constant and variable in braces", function() { + var result; + result = shouldEmberPrecompileToHelper('p.foo class={ :bar bar }'); + return ok(-1 !== result.indexOf('\'class\': (":foo :bar bar")')); +}); + +test("when ember expression is used with bind-attr", function() { + var result; + result = shouldEmberPrecompileToHelper('p.foo{ bind-attr class="bar" }'); + return ok(-1 !== result.indexOf('\'class\': (":foo bar")')); +}); + +test("when ember expression is used with bind-attr and multiple attrs", function() { + var result; + result = shouldEmberPrecompileToHelper('p.foo{ bind-attr something=bind class="bar" }'); + return ok(-1 !== result.indexOf('\'class\': (":foo bar")')); +}); + +test("only with bind-attr helper", function() { + var result; + result = shouldEmberPrecompileToHelper('p.foo{ someHelper class="bar" }', 'someHelper'); + ok(-1 !== result.indexOf('\'class\': ("bar")')); + return ok(-1 !== result.indexOf('class=\\"foo\\"')); +}); + +bindAttrHelper = function() { + var bindingString, k, options, param, params, v, _ref1; + options = arguments[arguments.length - 1]; + params = Array.prototype.slice.call(arguments, 0, -1); + bindingString = ""; + _ref1 = options.hash; + for (k in _ref1) { + if (!__hasProp.call(_ref1, k)) continue; + v = _ref1[k]; + bindingString += " " + k + " to " + v; + } + if (!bindingString) { + bindingString = " narf"; + } + param = params[0] || 'none'; + return "bind-attr" + bindingString; +}; + +Handlebars.registerHelper('bind-attr', bindAttrHelper); + +EmberHandlebars.registerHelper('bind-attr', bindAttrHelper); + +suite("bind-attr behavior for unquoted attribute values"); + +test("basic", function() { + var emblem; + emblem = 'p class=foo'; + shouldCompileTo(emblem, { + foo: "YEAH" + }, '

        '); + return shouldEmberPrecompileToHelper(emblem); +}); + +test("basic w/ underscore", function() { + var emblem; + emblem = 'p class=foo_urns'; + shouldCompileTo(emblem, { + foo_urns: "YEAH" + }, '

        '); + return shouldEmberPrecompileToHelper(emblem); +}); + +test("subproperties", function() { + var emblem; + emblem = 'p class=foo._death.woot'; + shouldCompileTo(emblem, { + foo: { + _death: { + woot: "YEAH" + } + } + }, '

        '); + return shouldEmberPrecompileToHelper(emblem); +}); + +test("multiple", function() { + return shouldCompileTo('p class=foo id="yup" data-thinger=yeah Hooray', { + foo: "FOO", + yeah: "YEAH" + }, '

        Hooray

        '); +}); + +test("class bind-attr special syntax", function() { + var emblem; + emblem = 'p class=foo:bar:baz'; + shouldEmberPrecompileToHelper(emblem); + return shouldThrow((function() { + return CompilerContext.compile(emblem); + })); +}); + +test("class bind-attr braced syntax w/ underscores and dashes", function() { + var emblem; + shouldEmberPrecompileToHelper('p class={f-oo:bar :b_az}'); + shouldEmberPrecompileToHelper('p class={ f-oo:bar :b_az }'); + shouldEmberPrecompileToHelper('p class={ f-oo:bar :b_az } Hello'); + emblem = ".input-prepend class={ filterOn:input-append }\n span.add-on"; + return shouldEmberPrecompileToHelper(emblem); +}); + +test("exclamation modifier (vanilla)", function() { + var emblem; + emblem = 'p class=foo!'; + return shouldCompileTo(emblem, { + foo: "YEAH" + }, '

        '); +}); + +test("exclamation modifier (ember)", function() { + var emblem, result; + emblem = 'p class=foo!'; + result = precompileEmber(emblem); + ok(result.match(/p class/)); + return ok(result.match(/helpers\.unbound.*foo/)); +}); + +suite("in-tag explicit mustache"); + +Handlebars.registerHelper('inTagHelper', function(p) { + return p; +}); + +test("single", function() { + return shouldCompileTo('p{inTagHelper foo}', { + foo: "ALEX" + }, '

        '); +}); + +test("double", function() { + return shouldCompileTo('p{inTagHelper foo}', { + foo: "ALEX" + }, '

        '); +}); + +test("triple", function() { + return shouldCompileTo('p{inTagHelper foo}', { + foo: "ALEX" + }, '

        '); +}); + +Handlebars.registerHelper('insertClass', function(p) { + return 'class="' + p + '"'; +}); + +test("with singlestache", function() { + return shouldCompileTo('p{insertClass foo} Hello', { + foo: "yar" + }, '

        Hello

        '); +}); + +test("singlestache can be used in text nodes", function() { + return shouldCompileTo('p Hello {dork}', '

        Hello {dork}

        '); +}); + +test("with doublestache", function() { + return shouldCompileTo('p{{insertClass foo}} Hello', { + foo: "yar" + }, '

        Hello

        '); +}); + +test("with triplestache", function() { + return shouldCompileTo('p{{{insertClass foo}}} Hello', { + foo: "yar" + }, '

        Hello

        '); +}); + +test("multiple", function() { + return shouldCompileTo('p{{{insertClass foo}}}{{{insertClass boo}}} Hello', { + foo: "yar", + boo: "nar" + }, '

        Hello

        '); +}); + +test("with nesting", function() { + var emblem; + emblem = "p{{bind-attr class=\"foo\"}}\n span Hello"; + return shouldCompileTo(emblem, { + foo: "yar" + }, '

        Hello

        '); +}); + +suite("actions"); + +Handlebars.registerHelper('action', function() { + var hashString, k, options, params, paramsString, v, _ref1; + options = arguments[arguments.length - 1]; + params = Array.prototype.slice.call(arguments, 0, -1); + hashString = ""; + paramsString = params.join('|'); + _ref1 = options.hash; + for (k in _ref1) { + if (!__hasProp.call(_ref1, k)) continue; + v = _ref1[k]; + hashString += " " + k + "=" + v; + } + if (!hashString) { + hashString = " nohash"; + } + return "action " + paramsString + hashString; +}); + +test("basic (click)", function() { + var emblem; + emblem = "button click=\"submitComment\" Submit Comment"; + return shouldCompileToString(emblem, ''); +}); + +test("basic (click) followed by attr", function() { + var emblem; + emblem = "button click=\"submitComment\" class=\"foo\" Submit Comment"; + shouldCompileToString(emblem, ''); + emblem = "button click=\"submitComment 'omg'\" class=\"foo\" Submit Comment"; + return shouldCompileToString(emblem, ''); +}); + +test("nested (mouseEnter)", function() { + var emblem; + emblem = "a mouseEnter='submitComment target=\"view\"'\n | Submit Comment"; + return shouldCompileToString(emblem, 'Submit Comment'); +}); + +test("nested (mouseEnter, doublequoted)", function() { + var emblem; + emblem = "a mouseEnter=\"submitComment target='view'\"\n | Submit Comment"; + return shouldCompileToString(emblem, 'Submit Comment'); +}); + +test("manual", function() { + var emblem; + emblem = "a{action submitComment target=\"view\"} Submit Comment"; + return shouldCompileToString(emblem, 'Submit Comment'); +}); + +test("manual nested", function() { + var emblem; + emblem = "a{action submitComment target=\"view\"}\n p Submit Comment"; + return shouldCompileToString(emblem, '

        Submit Comment

        '); +}); + +suite("haml style"); + +test("basic", function() { + var emblem; + emblem = "%borf"; + return shouldCompileToString(emblem, ''); +}); + +test("nested", function() { + var emblem; + emblem = "%borf\n %sporf Hello"; + return shouldCompileToString(emblem, 'Hello'); +}); + +test("capitalized", function() { + var emblem; + emblem = "%Alex alex\n%Alex\n %Woot"; + return shouldCompileToString(emblem, 'alex'); +}); + +test("funky chars", function() { + var emblem; + emblem = "%borf:narf\n%borf:narf Hello, {{foo}}.\n%alex = foo"; + return shouldCompileToString(emblem, { + foo: "Alex" + }, 'Hello, Alex.Alex'); +}); + +suite("line-based errors"); + +test("line number is provided for pegjs error", function() { + var emblem; + emblem = "p Hello\np Hello {{narf}"; + return shouldThrow((function() { + return CompilerContext.compile(emblem); + }), "line 2"); +}); + +test("single quote test", function() { + var emblem; + emblem = "button click='p' Frank\n \n/ form s='d target=\"App\"'\n label I'm a label!"; + return shouldCompileToString(emblem, ''); +}); + +test("double quote test", function() { + var emblem; + emblem = "button click=\"p\" Frank\n \n/ form s='d target=\"App\"'\n label I'm a label!"; + return shouldCompileToString(emblem, ''); +}); + +test("no quote test", function() { + var emblem; + emblem = "button click=p Frank\n \n/ form s='d target=\"App\"'\n label I'm a label!"; + return shouldCompileToString(emblem, ''); +}); + +suite("mustache DOM attribute shorthand"); + +test("tagName w/o space", function() { + var emblem, result; + emblem = "App.FunView%span"; + result = precompileEmber(emblem); + ok(result.match(/helpers\.view/)); + ok(result.match(/App\.FunView/)); + return ok(result.match(/tagName.*span/)); +}); + +test("tagName w/ space", function() { + var emblem, result; + emblem = "App.FunView %span"; + result = precompileEmber(emblem); + ok(result.match(/helpers\.view/)); + ok(result.match(/App\.FunView/)); + return ok(result.match(/tagName.*span/)); +}); + +test("tagName block", function() { + var emblem; + emblem = "view App.FunView%span\n p Hello"; + return shouldCompileToString(emblem, '

        Hello

        '); +}); + +test("class w/ space (needs space)", function() { + var emblem, result; + emblem = "App.FunView .bork"; + result = precompileEmber(emblem); + ok(result.match(/helpers\.view/)); + ok(result.match(/App\.FunView/)); + return ok(result.match(/class.*bork/)); +}); + +test("multiple classes", function() { + var emblem, result; + emblem = "App.FunView .bork.snork"; + result = precompileEmber(emblem); + ok(result.match(/helpers\.view/)); + ok(result.match(/App\.FunView/)); + return ok(result.match(/class.*bork.*snork/)); +}); + +test("elementId", function() { + var emblem, result; + emblem = "App.FunView#ohno"; + result = precompileEmber(emblem); + ok(result.match(/helpers\.view/)); + ok(result.match(/App\.FunView/)); + return ok(result.match(/elementId.*ohno/)); +}); + +test("mixed w/ hash`", function() { + var emblem, result; + emblem = "App.FunView .bork.snork funbags=\"yeah\""; + result = precompileEmber(emblem); + ok(result.match(/helpers\.view/)); + ok(result.match(/App\.FunView/)); + ok(result.match(/class.*bork.*snork/)); + ok(result.match(/hash/)); + ok(result.match(/funbags/)); + return ok(result.match(/yeah/)); +}); + +test("mixture of all`", function() { + var emblem, result; + emblem = "App.FunView%alex#hell.bork.snork funbags=\"yeah\""; + result = precompileEmber(emblem); + ok(result.match(/helpers\.view/)); + ok(result.match(/App\.FunView/)); + ok(result.match(/tagName.*alex/)); + ok(result.match(/elementId.*hell/)); + ok(result.match(/class.*bork.*snork/)); + ok(result.match(/hash/)); + ok(result.match(/funbags/)); + return ok(result.match(/yeah/)); +}); + +suite("self-closing html tags"); + +test("br", function() { + var emblem; + emblem = "br"; + return shouldCompileToString(emblem, '
        '); +}); + +test("br paragraph example", function() { + var emblem; + emblem = "p\n | LOL!\n br\n | BORF!"; + return shouldCompileToString(emblem, '

        LOL!
        BORF!

        '); +}); + +test("input", function() { + var emblem; + emblem = "input type=\"text\""; + return shouldCompileToString(emblem, ''); +}); + +suite("ember."); + +test("should precompile with EmberHandlebars", function() { + var emblem, result; + emblem = "input type=\"text\""; + result = Emblem.precompile(EmberHandlebars, 'p Hello').toString(); + return ok(result.match('

        Hello

        ')); +}); + +suite("old school handlebars"); + +test("array", function() { + var emblem, hash; + emblem = 'goodbyes\n | #{text}! \n| cruel #{world}!'; + hash = { + goodbyes: [ + { + text: "goodbye" + }, { + text: "Goodbye" + }, { + text: "GOODBYE" + } + ], + world: "world" + }; + shouldCompileToString(emblem, hash, "goodbye! Goodbye! GOODBYE! cruel world!"); + hash = { + goodbyes: [], + world: "world" + }; + return shouldCompileToString(emblem, hash, "cruel world!"); +}); + +Handlebars.registerPartial('hbPartial', '{{name}}'); + +test("calling handlebars partial", function() { + var emblem; + emblem = '> hbPartial\n| Hello #{> hbPartial}'; + return shouldCompileToString(emblem, { + id: 666, + name: "Death" + }, 'DeathHello Death'); +}); + +Emblem.registerPartial(Handlebars, 'emblemPartial', 'a href="/people/{{id}}" = name'); + +Emblem.registerPartial(Handlebars, 'emblemPartialB', 'p Grr'); + +Emblem.registerPartial(Handlebars, 'emblemPartialC', 'p = a'); + +test("calling emblem partial", function() { + return shouldCompileToString('> emblemPartial', { + id: 666, + name: "Death" + }, 'Death'); +}); + +test("calling emblem partial with context", function() { + return shouldCompileToString('> emblemPartialC foo', { + foo: { + a: "YES" + } + }, '

        YES

        '); +}); + +test("partials in mustaches", function() { + var emblem; + emblem = "| Hello, {{> emblemPartialC foo}}{{>emblemPartialB}}{{>emblemPartialB }}"; + return shouldCompileToString(emblem, { + foo: { + a: "YES" + } + }, 'Hello,

        YES

        Grr

        Grr

        '); +}); + +test("handlebars dot-separated paths with segment-literal notation", function() { + var emblem; + emblem = 'p = articles.[3]'; + return shouldCompileTo(emblem, { + articles: ['zero', 'one', 'two', 'three'] + }, '

        three

        '); +}); + +test("handlebars dot-separated paths with segment-literal notation, more nesting", function() { + var emblem; + emblem = 'p = articles.[3].[#comments].[0]'; + return shouldCompileTo(emblem, { + articles: [ + {}, {}, {}, { + '#comments': ['bazinga'] + } + ] + }, '

        bazinga

        '); +}); + +test("../path as inMustacheParam recognized correctly as pathIdNode instead of classShorthand", function() { + var emblem; + Handlebars.registerHelper('jumpToParent', function(link) { + return new Handlebars.SafeString("Jump to parent top"); + }); + emblem = 'each children\n jumpToParent ../parentLink'; + return shouldCompileTo(emblem, { + parentLink: '#anchor', + children: [{}] + }, 'Jump to parent top'); +}); + +test("block as #each", function() { + var emblem; + emblem = 'thangs\n p Woot #{yeah}'; + return shouldCompileToString(emblem, { + thangs: [ + { + yeah: 123 + }, { + yeah: 456 + } + ] + }, '

        Woot 123

        Woot 456

        '); +}); + +if (supportsEachHelperDataKeywords) { + suite("each block helper keywords prefixed by @"); + test("#each with @index", function() { + var emblem; + emblem = 'thangs\n p #{@index} Woot #{yeah}'; + return shouldCompileToString(emblem, { + thangs: [ + { + yeah: 123 + }, { + yeah: 456 + } + ] + }, '

        0 Woot 123

        1 Woot 456

        '); + }); + test("#each with @key", function() { + var emblem; + emblem = 'each thangs\n p #{@key}: #{this}'; + return shouldCompileTo(emblem, { + thangs: { + '@key': 123, + 'works!': 456 + } + }, '

        @key: 123

        works!: 456

        '); + }); + test("#each with @key, @index", function() { + var emblem; + emblem = 'each thangs\n p #{@index} #{@key}: #{this}'; + return shouldCompileTo(emblem, { + thangs: { + '@key': 123, + 'works!': 456 + } + }, '

        0 @key: 123

        1 works!: 456

        '); + }); + test("#each with @key, @first", function() { + var emblem; + emblem = 'each thangs\n if @first\n p First item\n else\n p #{@key}: #{this}'; + return shouldCompileTo(emblem, { + thangs: { + '@key': 123, + 'works!': 456 + } + }, '

        First item

        works!: 456

        '); + }); +} + +/* +test "partial in block", -> + emblem = + """ + ul = people + > link + """ + data = + people: [ + { "name": "Alan", "id": 1 } + { "name": "Yehuda", "id": 2 } + ] + shouldCompileToString emblem, data, '
          AlanYehuda
            ' +*/ + + +suite("inline block helper"); + +test("text only", function() { + var emblem; + emblem = "view SomeView | Hello"; + return shouldCompileToString(emblem, 'Hello'); +}); + +test("multiline", function() { + var emblem; + emblem = "view SomeView | Hello, \n How are you? \n Sup?"; + return shouldCompileToString(emblem, 'Hello, How are you? Sup?'); +}); + +test("more complicated", function() { + var emblem; + emblem = "view SomeView borf=\"yes\" | Hello, \n How are you? \n Sup?"; + return shouldCompileToString(emblem, 'Hello, How are you? Sup?'); +}); + +suite("copy paste html"); + +test("indented", function() { + var emblem; + emblem = "

            \n This be some text\n Basic HTML Sample Page\n

            "; + return shouldCompileToString(emblem, '

            This be some textBasic HTML Sample Page

            '); +}); + +test("flatlina", function() { + var emblem; + emblem = "

            \nThis be some text\nBasic HTML Sample Page\n

            "; + return shouldCompileToString(emblem, '

            This be some textBasic HTML Sample Page

            '); +}); + +test("bigass", function() { + var emblem, expected; + expect(0); + return "PENDING"; + emblem = "
            \n

            \n We design and develop ambitious web and mobile applications, \n

            \n

            \n A more official portfolio page is on its way, but in the meantime, \n check out\n

            \n
            "; + expected = '

            We design and develop ambitious web and mobile applications,

            A more official portfolio page is on its way, but in the meantime, check out

            '; + return shouldCompileToString(emblem, expected); +}); + +suite("`this` keyword"); + +test("basic", function() { + var emblem; + emblem = 'each foo\n p = this\n this'; + return shouldCompileTo(emblem, { + foo: ["Alex", "Emily"] + }, '

            Alex

            Alex

            Emily

            Emily'); +}); + +suite("colon separator"); + +test("basic", function() { + var emblem; + emblem = 'each foo: p Hello, #{this}'; + return shouldCompileTo(emblem, { + foo: ["Alex", "Emily", "Nicole"] + }, '

            Hello, Alex

            Hello, Emily

            Hello, Nicole

            '); +}); + +test("html stack", function() { + var emblem; + emblem = '.container: .row: .span5: span Hello'; + return shouldCompileToString(emblem, '
            Hello
            '); +}); + +test("epic", function() { + var emblem; + emblem = '.container: .row: .span5\n ul#list data-foo="yes": each foo: li\n span: this'; + return shouldCompileTo(emblem, { + foo: ["a", "b"] + }, '
            • a
            • b
            '); +}); + +test("html stack elements only", function() { + var emblem; + emblem = 'p: span: div: p: foo'; + return shouldCompileToString(emblem, { + foo: "alex" + }, '

            alex

            '); +}); + +test("mixed separators", function() { + var emblem; + emblem = '.fun = each foo: %nork = this'; + return shouldCompileTo(emblem, { + foo: ["Alex", "Emily", "Nicole"] + }, '
            AlexEmilyNicole
            '); +}); + +test("mixed separators rewritten", function() { + var emblem; + emblem = '.fun: each foo: %nork: this'; + return shouldCompileTo(emblem, { + foo: ["Alex", "Emily", "Nicole"] + }, '
            AlexEmilyNicole
            '); +}); + +test("with text terminator", function() { + var emblem; + emblem = '.fun: view SomeView | Hello'; + return shouldCompileToString(emblem, '
            Hello
            '); +}); + +test("test from heartsentwined", function() { + shouldCompileTo('li data-foo=bar: a', { + bar: "abc" + }, '
          • '); + return shouldCompileTo("li data-foo='bar': a", '
          • '); +}); + +test("mixture of colon and indentation", function() { + var emblem; + emblem = "li data-foo=bar: a\n baz"; + return shouldCompileTo(emblem, { + bar: "abc", + baz: "Hello" + }, '
          • Hello
          • '); +}); + +test("mixture of colon and indentation pt.2", function() { + var emblem, result; + emblem = "ul\n li data-foo=bar: a quux\n li data-foo='bar': a quux\n li data-foo=bar href='#': a quux"; + result = precompileEmber(emblem); + return ok(!result.match("a quux")); +}); + +suite("base indent / predent"); + +test("predent", function() { + var emblem, s; + emblem = " \n"; + s = "pre\n ` This\n ` should\n ` hopefully\n ` work, and work well.\n"; + emblem += s; + return shouldCompileToString(emblem, '
            This\n  should\n hopefully\n   work, and work well.\n
            '); +}); + +test("mixture", function() { + var emblem; + emblem = " \n"; + emblem += " p Hello\n"; + emblem += " p\n"; + emblem += " | Woot\n"; + emblem += " span yes\n"; + return shouldCompileToString(emblem, '

            Hello

            Woot

            yes'); +}); + +test("mixture w/o opening blank", function() { + var emblem; + emblem = " p Hello\n"; + emblem += " p\n"; + emblem += " | Woot\n"; + emblem += " span yes\n"; + return shouldCompileToString(emblem, '

            Hello

            Woot

            yes'); +}); + +test("w/ blank lines", function() { + var emblem; + emblem = " p Hello\n"; + emblem += " p\n"; + emblem += "\n"; + emblem += " | Woot\n"; + emblem += "\n"; + emblem += " span yes\n"; + return shouldCompileToString(emblem, '

            Hello

            Woot

            yes'); +}); + +test("w/ blank whitespaced lines", function() { + var emblem; + emblem = " p Hello\n"; + emblem += " p\n"; + emblem += "\n"; + emblem += " | Woot\n"; + emblem += " \n"; + emblem += " \n"; + emblem += " \n"; + emblem += "\n"; + emblem += " span yes\n"; + emblem += "\n"; + emblem += " sally\n"; + emblem += "\n"; + emblem += " \n"; + emblem += " | Woot\n"; + return shouldCompileToString(emblem, '

            Hello

            Woot

            yesWoot'); +}); + +suite("EOL Whitespace"); + +test("shouldn't be necessary to insert a space", function() { + var emblem; + emblem = "p Hello,\n How are you?\np I'm fine, thank you."; + return shouldCompileToString(emblem, "

            Hello, How are you?

            I'm fine, thank you.

            "); +}); + +suite("misc."); + +test("end with indent", function() { + var emblem; + expect(0); + return "PENDING"; + emblem = "div\n p\n span Butts\n em fpokasd\n iunw\n paosdk"; + return shouldCompileToString(emblem, '

            Buttsem fpokasdiunw paosdk

            '); +}); + +test("capitalized view helper should not kick in if suffix modifiers present", function() { + var emblem; + emblem = "Foo!"; + return shouldCompileToString(emblem, 'Foo'); +}); + +test("GH-26: no need for space before equal sign", function() { + var emblem; + emblem = "span= foo"; + shouldCompileToString(emblem, { + foo: "YEAH" + }, 'YEAH'); + emblem = "span.foo= foo"; + shouldCompileToString(emblem, { + foo: "YEAH" + }, 'YEAH'); + emblem = "span#hooray.foo= foo"; + shouldCompileToString(emblem, { + foo: "YEAH" + }, 'YEAH'); + emblem = "#hooray= foo"; + shouldCompileToString(emblem, { + foo: "YEAH" + }, '
            YEAH
            '); + emblem = ".hooray= foo"; + return shouldCompileToString(emblem, { + foo: "YEAH" + }, '
            YEAH
            '); +}); + +test("numbers in shorthand", function() { + shouldCompileToString('#4a', '
            '); + shouldCompileToString('.4a', '
            '); + shouldCompileToString('.4', '
            '); + shouldCompileToString('#4', '
            '); + shouldCompileToString('%4', '<4>'); + shouldCompileToString('%4 ermagerd', '<4>ermagerd'); + return shouldCompileToString('%4#4.4 ermagerd', '<4 id="4" class="4">ermagerd'); +}); + +test("Emblem has a VERSION defined", function() { + return ok(Emblem.VERSION, "Emblem.VERSION should be defined"); +}); + +test("Windows line endings", function() { + var emblem; + emblem = ".navigation\r\n p Hello\r\n#main\r\n | hi"; + return shouldCompileToString(emblem, '
            hi
            '); +}); + +test("backslash doesn't cause infinite loop", function() { + var emblem; + emblem = '| \\'; + return shouldCompileTo(emblem, "\\"); +}); + +test("backslash doesn't cause infinite loop with letter", function() { + var emblem; + emblem = '| \\a'; + return shouldCompileTo(emblem, "\\a"); +}); + +test("self closing tag with forward slash", function() { + var emblem; + emblem = 'p/\n%bork/\n.omg/\n#hello.boo/\np/ class="asdasd"'; + return shouldCompileTo(emblem, '

            '); +}); + +test("tagnames and attributes with colons", function() { + var emblem; + emblem = '%al:ex match:neer="snork" Hello!'; + return shouldCompileTo(emblem, 'Hello!'); +}); + +test("windows newlines", function() { + var emblem; + emblem = "\r\n \r\n p Hello\r\n\r\n"; + return shouldCompileTo(emblem, '

            Hello

            '); +}); + +if (supportsSubexpressions) { + suite("subexpressions"); + Handlebars.registerHelper('echo', function(param) { + return "ECHO " + param; + }); + Handlebars.registerHelper('echofun', function() { + var options; + options = Array.prototype.pop.call(arguments); + return "FUN = " + options.hash.fun; + }); + Handlebars.registerHelper('hello', function(param) { + return "hello"; + }); + Handlebars.registerHelper('equal', function(x, y) { + return x === y; + }); + test("arg-less helper", function() { + var emblem; + emblem = 'p {{echo (hello)}}'; + shouldCompileTo(emblem, '

            ECHO hello

            '); + emblem = '= echo (hello)'; + return shouldCompileTo(emblem, 'ECHO hello'); + }); + test("helper w args", function() { + var emblem; + emblem = 'p {{echo (equal 1 1)}}'; + shouldCompileTo(emblem, '

            ECHO true

            '); + emblem = '= echo (equal 1 1)'; + return shouldCompileTo(emblem, 'ECHO true'); + }); + test("supports much nesting", function() { + var emblem; + emblem = 'p {{echo (equal (equal 1 1) true)}}'; + shouldCompileTo(emblem, '

            ECHO true

            '); + emblem = '= echo (equal (equal 1 1) true)'; + return shouldCompileTo(emblem, 'ECHO true'); + }); + test("with hashes", function() { + var emblem; + emblem = 'p {{echo (equal (equal 1 1) true fun="yes")}}'; + shouldCompileTo(emblem, '

            ECHO true

            '); + emblem = '= echo (equal (equal 1 1) true fun="yes")'; + return shouldCompileTo(emblem, 'ECHO true'); + }); + test("as hashes", function() { + var emblem; + emblem = 'p {{echofun fun=(equal 1 1)}}'; + shouldCompileTo(emblem, '

            FUN = true

            '); + emblem = '= echofun fun=(equal 1 1)'; + return shouldCompileTo(emblem, 'FUN = true'); + }); + test("complex expression", function() { + var emblem; + emblem = 'p {{echofun true (hello how="are" you=false) 1 not=true fun=(equal "ECHO hello" (echo (hello))) win="yes"}}'; + shouldCompileTo(emblem, '

            FUN = true

            '); + emblem = '= echofun true (hello how="are" you=false) 1 not=true fun=(equal "ECHO hello" (echo (hello))) win="yes"'; + return shouldCompileTo(emblem, 'FUN = true'); + }); +} diff --git a/bower_components/emblem/test/resources/browser/ember-1.2.0.js b/bower_components/emblem/test/resources/browser/ember-1.2.0.js new file mode 100644 index 0000000..980909c --- /dev/null +++ b/bower_components/emblem/test/resources/browser/ember-1.2.0.js @@ -0,0 +1,38407 @@ +// ========================================================================== +// Project: Ember - JavaScript Application Framework +// Copyright: Copyright 2011-2013 Tilde Inc. and contributors +// Portions Copyright 2006-2011 Strobe Inc. +// Portions Copyright 2008-2011 Apple Inc. All rights reserved. +// License: Licensed under MIT license +// See https://raw.github.com/emberjs/ember.js/master/LICENSE +// ========================================================================== + + + // Version: 1.2.0 + +(function() { +/*global __fail__*/ + +/** +Ember Debug + +@module ember +@submodule ember-debug +*/ + +/** +@class Ember +*/ + +if ('undefined' === typeof Ember) { + Ember = {}; + + if ('undefined' !== typeof window) { + window.Em = window.Ember = Em = Ember; + } +} + +Ember.ENV = 'undefined' === typeof ENV ? {} : ENV; + +if (!('MANDATORY_SETTER' in Ember.ENV)) { + Ember.ENV.MANDATORY_SETTER = true; // default to true for debug dist +} + +/** + Define an assertion that will throw an exception if the condition is not + met. Ember build tools will remove any calls to `Ember.assert()` when + doing a production build. Example: + + ```javascript + // Test for truthiness + Ember.assert('Must pass a valid object', obj); + // Fail unconditionally + Ember.assert('This code path should never be run') + ``` + + @method assert + @param {String} desc A description of the assertion. This will become + the text of the Error thrown if the assertion fails. + @param {Boolean} test Must be truthy for the assertion to pass. If + falsy, an exception will be thrown. +*/ +Ember.assert = function(desc, test) { + if (!test) { + Ember.Logger.assert(test, desc); + } + + if (Ember.testing && !test) { + // when testing, ensure test failures when assertions fail + throw new Ember.Error("Assertion Failed: " + desc); + } +}; + + +/** + Display a warning with the provided message. Ember build tools will + remove any calls to `Ember.warn()` when doing a production build. + + @method warn + @param {String} message A warning to display. + @param {Boolean} test An optional boolean. If falsy, the warning + will be displayed. +*/ +Ember.warn = function(message, test) { + if (!test) { + Ember.Logger.warn("WARNING: "+message); + if ('trace' in Ember.Logger) Ember.Logger.trace(); + } +}; + +/** + Display a debug notice. Ember build tools will remove any calls to + `Ember.debug()` when doing a production build. + + ```javascript + Ember.debug("I'm a debug notice!"); + ``` + + @method debug + @param {String} message A debug message to display. +*/ +Ember.debug = function(message) { + Ember.Logger.debug("DEBUG: "+message); +}; + +/** + Display a deprecation warning with the provided message and a stack trace + (Chrome and Firefox only). Ember build tools will remove any calls to + `Ember.deprecate()` when doing a production build. + + @method deprecate + @param {String} message A description of the deprecation. + @param {Boolean} test An optional boolean. If falsy, the deprecation + will be displayed. +*/ +Ember.deprecate = function(message, test) { + if (Ember.TESTING_DEPRECATION) { return; } + + if (arguments.length === 1) { test = false; } + if (test) { return; } + + if (Ember.ENV.RAISE_ON_DEPRECATION) { throw new Ember.Error(message); } + + var error; + + // When using new Error, we can't do the arguments check for Chrome. Alternatives are welcome + try { __fail__.fail(); } catch (e) { error = e; } + + if (Ember.LOG_STACKTRACE_ON_DEPRECATION && error.stack) { + var stack, stackStr = ''; + if (error['arguments']) { + // Chrome + stack = error.stack.replace(/^\s+at\s+/gm, ''). + replace(/^([^\(]+?)([\n$])/gm, '{anonymous}($1)$2'). + replace(/^Object.\s*\(([^\)]+)\)/gm, '{anonymous}($1)').split('\n'); + stack.shift(); + } else { + // Firefox + stack = error.stack.replace(/(?:\n@:0)?\s+$/m, ''). + replace(/^\(/gm, '{anonymous}(').split('\n'); + } + + stackStr = "\n " + stack.slice(2).join("\n "); + message = message + stackStr; + } + + Ember.Logger.warn("DEPRECATION: "+message); +}; + + + +/** + Alias an old, deprecated method with its new counterpart. + + Display a deprecation warning with the provided message and a stack trace + (Chrome and Firefox only) when the assigned method is called. + + Ember build tools will not remove calls to `Ember.deprecateFunc()`, though + no warnings will be shown in production. + + ```javascript + Ember.oldMethod = Ember.deprecateFunc("Please use the new, updated method", Ember.newMethod); + ``` + + @method deprecateFunc + @param {String} message A description of the deprecation. + @param {Function} func The new function called to replace its deprecated counterpart. + @return {Function} a new function that wrapped the original function with a deprecation warning +*/ +Ember.deprecateFunc = function(message, func) { + return function() { + Ember.deprecate(message); + return func.apply(this, arguments); + }; +}; + + +// Inform the developer about the Ember Inspector if not installed. +if (!Ember.testing) { + if (typeof window !== 'undefined' && window.chrome && window.addEventListener) { + window.addEventListener("load", function() { + if (document.body && document.body.dataset && !document.body.dataset.emberExtension) { + Ember.debug('For more advanced debugging, install the Ember Inspector from https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi'); + } + }, false); + } +} + +})(); + +// ========================================================================== +// Project: Ember - JavaScript Application Framework +// Copyright: Copyright 2011-2013 Tilde Inc. and contributors +// Portions Copyright 2006-2011 Strobe Inc. +// Portions Copyright 2008-2011 Apple Inc. All rights reserved. +// License: Licensed under MIT license +// See https://raw.github.com/emberjs/ember.js/master/LICENSE +// ========================================================================== + + + // Version: 1.2.0 + +(function() { +var define, requireModule; + +(function() { + var registry = {}, seen = {}; + + define = function(name, deps, callback) { + registry[name] = { deps: deps, callback: callback }; + }; + + requireModule = function(name) { + if (seen[name]) { return seen[name]; } + seen[name] = {}; + + var mod, deps, callback, reified, exports; + + mod = registry[name]; + + if (!mod) { + throw new Error("Module '" + name + "' not found."); + } + + deps = mod.deps; + callback = mod.callback; + reified = []; + + for (var i=0, l=deps.length; i -1; +}; + +// From: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/map +var arrayMap = isNativeFunc(Array.prototype.map) ? Array.prototype.map : function(fun /*, thisp */) { + //"use strict"; + + if (this === void 0 || this === null) { + throw new TypeError(); + } + + var t = Object(this); + var len = t.length >>> 0; + if (typeof fun !== "function") { + throw new TypeError(); + } + + var res = new Array(len); + var thisp = arguments[1]; + for (var i = 0; i < len; i++) { + if (i in t) { + res[i] = fun.call(thisp, t[i], i, t); + } + } + + return res; +}; + +// From: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/foreach +var arrayForEach = isNativeFunc(Array.prototype.forEach) ? Array.prototype.forEach : function(fun /*, thisp */) { + //"use strict"; + + if (this === void 0 || this === null) { + throw new TypeError(); + } + + var t = Object(this); + var len = t.length >>> 0; + if (typeof fun !== "function") { + throw new TypeError(); + } + + var thisp = arguments[1]; + for (var i = 0; i < len; i++) { + if (i in t) { + fun.call(thisp, t[i], i, t); + } + } +}; + +var arrayIndexOf = isNativeFunc(Array.prototype.indexOf) ? Array.prototype.indexOf : function (obj, fromIndex) { + if (fromIndex === null || fromIndex === undefined) { fromIndex = 0; } + else if (fromIndex < 0) { fromIndex = Math.max(0, this.length + fromIndex); } + for (var i = fromIndex, j = this.length; i < j; i++) { + if (this[i] === obj) { return i; } + } + return -1; +}; + +/** + Array polyfills to support ES5 features in older browsers. + + @namespace Ember + @property ArrayPolyfills +*/ +Ember.ArrayPolyfills = { + map: arrayMap, + forEach: arrayForEach, + indexOf: arrayIndexOf +}; + +if (Ember.SHIM_ES5) { + if (!Array.prototype.map) { + Array.prototype.map = arrayMap; + } + + if (!Array.prototype.forEach) { + Array.prototype.forEach = arrayForEach; + } + + if (!Array.prototype.indexOf) { + Array.prototype.indexOf = arrayIndexOf; + } +} + +})(); + + + +(function() { +var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; + +/** + A subclass of the JavaScript Error object for use in Ember. + + @class Error + @namespace Ember + @extends Error + @constructor +*/ +Ember.Error = function() { + var tmp = Error.apply(this, arguments); + + // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. + for (var idx = 0; idx < errorProps.length; idx++) { + this[errorProps[idx]] = tmp[errorProps[idx]]; + } +}; + +Ember.Error.prototype = Ember.create(Error.prototype); + +// .......................................................... +// ERROR HANDLING +// + +/** + A function may be assigned to `Ember.onerror` to be called when Ember + internals encounter an error. This is useful for specialized error handling + and reporting code. + + ```javascript + Ember.onerror = function(error) { + Em.$.ajax('/report-error', 'POST', { + stack: error.stack, + otherInformation: 'whatever app state you want to provide' + }); + }; + ``` + + @event onerror + @for Ember + @param {Exception} error the error object +*/ +Ember.onerror = null; + +/** + @private + + Wrap code block in a try/catch if `Ember.onerror` is set. + + @method handleErrors + @for Ember + @param {Function} func + @param [context] +*/ +Ember.handleErrors = function(func, context) { + // Unfortunately in some browsers we lose the backtrace if we rethrow the existing error, + // so in the event that we don't have an `onerror` handler we don't wrap in a try/catch + if ('function' === typeof Ember.onerror) { + try { + return func.call(context || this); + } catch (error) { + Ember.onerror(error); + } + } else { + return func.call(context || this); + } +}; + +})(); + + + +(function() { +/** +@module ember-metal +*/ + +/** + @private + + Prefix used for guids through out Ember. + +*/ +Ember.GUID_PREFIX = 'ember'; + + +var o_defineProperty = Ember.platform.defineProperty, + o_create = Ember.create, + // Used for guid generation... + GUID_KEY = '__ember'+ (+ new Date()), + uuid = 0, + numberCache = [], + stringCache = {}; + +var MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER; + +/** + @private + + A unique key used to assign guids and other private metadata to objects. + If you inspect an object in your browser debugger you will often see these. + They can be safely ignored. + + On browsers that support it, these properties are added with enumeration + disabled so they won't show up when you iterate over your properties. + + @property GUID_KEY + @for Ember + @type String + @final +*/ +Ember.GUID_KEY = GUID_KEY; + +var GUID_DESC = { + writable: false, + configurable: false, + enumerable: false, + value: null +}; + +/** + @private + + Generates a new guid, optionally saving the guid to the object that you + pass in. You will rarely need to use this method. Instead you should + call `Ember.guidFor(obj)`, which return an existing guid if available. + + @method generateGuid + @for Ember + @param {Object} [obj] Object the guid will be used for. If passed in, the guid will + be saved on the object and reused whenever you pass the same object + again. + + If no object is passed, just generate a new guid. + @param {String} [prefix] Prefix to place in front of the guid. Useful when you want to + separate the guid into separate namespaces. + @return {String} the guid +*/ +Ember.generateGuid = function generateGuid(obj, prefix) { + if (!prefix) prefix = Ember.GUID_PREFIX; + var ret = (prefix + (uuid++)); + if (obj) { + GUID_DESC.value = ret; + o_defineProperty(obj, GUID_KEY, GUID_DESC); + } + return ret; +}; + +/** + @private + + Returns a unique id for the object. If the object does not yet have a guid, + one will be assigned to it. You can call this on any object, + `Ember.Object`-based or not, but be aware that it will add a `_guid` + property. + + You can also use this method on DOM Element objects. + + @method guidFor + @for Ember + @param {Object} obj any object, string, number, Element, or primitive + @return {String} the unique guid for this instance. +*/ +Ember.guidFor = function guidFor(obj) { + + // special cases where we don't want to add a key to object + if (obj === undefined) return "(undefined)"; + if (obj === null) return "(null)"; + + var ret; + var type = typeof obj; + + // Don't allow prototype changes to String etc. to change the guidFor + switch(type) { + case 'number': + ret = numberCache[obj]; + if (!ret) ret = numberCache[obj] = 'nu'+obj; + return ret; + + case 'string': + ret = stringCache[obj]; + if (!ret) ret = stringCache[obj] = 'st'+(uuid++); + return ret; + + case 'boolean': + return obj ? '(true)' : '(false)'; + + default: + if (obj[GUID_KEY]) return obj[GUID_KEY]; + if (obj === Object) return '(Object)'; + if (obj === Array) return '(Array)'; + ret = 'ember'+(uuid++); + GUID_DESC.value = ret; + o_defineProperty(obj, GUID_KEY, GUID_DESC); + return ret; + } +}; + +// .......................................................... +// META +// + +var META_DESC = { + writable: true, + configurable: false, + enumerable: false, + value: null +}; + +var META_KEY = Ember.GUID_KEY+'_meta'; + +/** + The key used to store meta information on object for property observing. + + @property META_KEY + @for Ember + @private + @final + @type String +*/ +Ember.META_KEY = META_KEY; + +// Placeholder for non-writable metas. +var EMPTY_META = { + descs: {}, + watching: {} +}; + +if (MANDATORY_SETTER) { EMPTY_META.values = {}; } + +Ember.EMPTY_META = EMPTY_META; + +if (Object.freeze) Object.freeze(EMPTY_META); + +var isDefinePropertySimulated = Ember.platform.defineProperty.isSimulated; + +function Meta(obj) { + this.descs = {}; + this.watching = {}; + this.cache = {}; + this.source = obj; +} + +if (isDefinePropertySimulated) { + // on platforms that don't support enumerable false + // make meta fail jQuery.isPlainObject() to hide from + // jQuery.extend() by having a property that fails + // hasOwnProperty check. + Meta.prototype.__preventPlainObject__ = true; + + // Without non-enumerable properties, meta objects will be output in JSON + // unless explicitly suppressed + Meta.prototype.toJSON = function () { }; +} + +/** + Retrieves the meta hash for an object. If `writable` is true ensures the + hash is writable for this object as well. + + The meta object contains information about computed property descriptors as + well as any watched properties and other information. You generally will + not access this information directly but instead work with higher level + methods that manipulate this hash indirectly. + + @method meta + @for Ember + @private + + @param {Object} obj The object to retrieve meta for + @param {Boolean} [writable=true] Pass `false` if you do not intend to modify + the meta hash, allowing the method to avoid making an unnecessary copy. + @return {Object} the meta hash for an object +*/ +Ember.meta = function meta(obj, writable) { + + var ret = obj[META_KEY]; + if (writable===false) return ret || EMPTY_META; + + if (!ret) { + if (!isDefinePropertySimulated) o_defineProperty(obj, META_KEY, META_DESC); + + ret = new Meta(obj); + + if (MANDATORY_SETTER) { ret.values = {}; } + + obj[META_KEY] = ret; + + // make sure we don't accidentally try to create constructor like desc + ret.descs.constructor = null; + + } else if (ret.source !== obj) { + if (!isDefinePropertySimulated) o_defineProperty(obj, META_KEY, META_DESC); + + ret = o_create(ret); + ret.descs = o_create(ret.descs); + ret.watching = o_create(ret.watching); + ret.cache = {}; + ret.source = obj; + + if (MANDATORY_SETTER) { ret.values = o_create(ret.values); } + + obj[META_KEY] = ret; + } + return ret; +}; + +Ember.getMeta = function getMeta(obj, property) { + var meta = Ember.meta(obj, false); + return meta[property]; +}; + +Ember.setMeta = function setMeta(obj, property, value) { + var meta = Ember.meta(obj, true); + meta[property] = value; + return value; +}; + +/** + @deprecated + @private + + In order to store defaults for a class, a prototype may need to create + a default meta object, which will be inherited by any objects instantiated + from the class's constructor. + + However, the properties of that meta object are only shallow-cloned, + so if a property is a hash (like the event system's `listeners` hash), + it will by default be shared across all instances of that class. + + This method allows extensions to deeply clone a series of nested hashes or + other complex objects. For instance, the event system might pass + `['listeners', 'foo:change', 'ember157']` to `prepareMetaPath`, which will + walk down the keys provided. + + For each key, if the key does not exist, it is created. If it already + exists and it was inherited from its constructor, the constructor's + key is cloned. + + You can also pass false for `writable`, which will simply return + undefined if `prepareMetaPath` discovers any part of the path that + shared or undefined. + + @method metaPath + @for Ember + @param {Object} obj The object whose meta we are examining + @param {Array} path An array of keys to walk down + @param {Boolean} writable whether or not to create a new meta + (or meta property) if one does not already exist or if it's + shared with its constructor +*/ +Ember.metaPath = function metaPath(obj, path, writable) { + Ember.deprecate("Ember.metaPath is deprecated and will be removed from future releases."); + var meta = Ember.meta(obj, writable), keyName, value; + + for (var i=0, l=path.length; i size ? size : ends; + if (count <= 0) { count = 0; } + + chunk = args.splice(0, size); + chunk = [start, count].concat(chunk); + + start += size; + ends -= count; + + ret = ret.concat(splice.apply(array, chunk)); + } + return ret; + }, + + replace: function(array, idx, amt, objects) { + if (array.replace) { + return array.replace(idx, amt, objects); + } else { + return utils._replace(array, idx, amt, objects); + } + }, + + intersection: function(array1, array2) { + var intersection = []; + + utils.forEach(array1, function(element) { + if (utils.indexOf(array2, element) >= 0) { + intersection.push(element); + } + }); + + return intersection; + } +}; + +})(); + + + +(function() { +/** +@module ember-metal +*/ + +var META_KEY = Ember.META_KEY, get; + +var MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER; + +var IS_GLOBAL_PATH = /^([A-Z$]|([0-9][A-Z$])).*[\.\*]/; +var HAS_THIS = /^this[\.\*]/; +var FIRST_KEY = /^([^\.\*]+)/; + +// .......................................................... +// GET AND SET +// +// If we are on a platform that supports accessors we can use those. +// Otherwise simulate accessors by looking up the property directly on the +// object. + +/** + Gets the value of a property on an object. If the property is computed, + the function will be invoked. If the property is not defined but the + object implements the `unknownProperty` method then that will be invoked. + + If you plan to run on IE8 and older browsers then you should use this + method anytime you want to retrieve a property on an object that you don't + know for sure is private. (Properties beginning with an underscore '_' + are considered private.) + + On all newer browsers, you only need to use this method to retrieve + properties if the property might not be defined on the object and you want + to respect the `unknownProperty` handler. Otherwise you can ignore this + method. + + Note that if the object itself is `undefined`, this method will throw + an error. + + @method get + @for Ember + @param {Object} obj The object to retrieve from. + @param {String} keyName The property key to retrieve + @return {Object} the property value or `null`. +*/ +get = function get(obj, keyName) { + // Helpers that operate with 'this' within an #each + if (keyName === '') { + return obj; + } + + if (!keyName && 'string'===typeof obj) { + keyName = obj; + obj = null; + } + + Ember.assert("Cannot call get with "+ keyName +" key.", !!keyName); + Ember.assert("Cannot call get with '"+ keyName +"' on an undefined object.", obj !== undefined); + + if (obj === null || keyName.indexOf('.') !== -1) { + return getPath(obj, keyName); + } + + var meta = obj[META_KEY], desc = meta && meta.descs[keyName], ret; + if (desc) { + return desc.get(obj, keyName); + } else { + if (MANDATORY_SETTER && meta && meta.watching[keyName] > 0) { + ret = meta.values[keyName]; + } else { + ret = obj[keyName]; + } + + if (ret === undefined && + 'object' === typeof obj && !(keyName in obj) && 'function' === typeof obj.unknownProperty) { + return obj.unknownProperty(keyName); + } + + return ret; + } +}; + +// Currently used only by Ember Data tests +if (Ember.config.overrideAccessors) { + Ember.get = get; + Ember.config.overrideAccessors(); + get = Ember.get; +} + +/** + @private + + Normalizes a target/path pair to reflect that actual target/path that should + be observed, etc. This takes into account passing in global property + paths (i.e. a path beginning with a captial letter not defined on the + target) and * separators. + + @method normalizeTuple + @for Ember + @param {Object} target The current target. May be `null`. + @param {String} path A path on the target or a global property path. + @return {Array} a temporary array with the normalized target/path pair. +*/ +var normalizeTuple = Ember.normalizeTuple = function(target, path) { + var hasThis = HAS_THIS.test(path), + isGlobal = !hasThis && IS_GLOBAL_PATH.test(path), + key; + + if (!target || isGlobal) target = Ember.lookup; + if (hasThis) path = path.slice(5); + + if (target === Ember.lookup) { + key = path.match(FIRST_KEY)[0]; + target = get(target, key); + path = path.slice(key.length+1); + } + + // must return some kind of path to be valid else other things will break. + if (!path || path.length===0) throw new Ember.Error('Invalid Path'); + + return [ target, path ]; +}; + +var getPath = Ember._getPath = function(root, path) { + var hasThis, parts, tuple, idx, len; + + // If there is no root and path is a key name, return that + // property from the global object. + // E.g. get('Ember') -> Ember + if (root === null && path.indexOf('.') === -1) { return get(Ember.lookup, path); } + + // detect complicated paths and normalize them + hasThis = HAS_THIS.test(path); + + if (!root || hasThis) { + tuple = normalizeTuple(root, path); + root = tuple[0]; + path = tuple[1]; + tuple.length = 0; + } + + parts = path.split("."); + len = parts.length; + for (idx = 0; root != null && idx < len; idx++) { + root = get(root, parts[idx], true); + if (root && root.isDestroyed) { return undefined; } + } + return root; +}; + +Ember.getWithDefault = function(root, key, defaultValue) { + var value = get(root, key); + + if (value === undefined) { return defaultValue; } + return value; +}; + + +Ember.get = get; + +})(); + + + +(function() { +/** +@module ember-metal +*/ + +var o_create = Ember.create, + metaFor = Ember.meta, + META_KEY = Ember.META_KEY, + a_slice = [].slice, + /* listener flags */ + ONCE = 1, SUSPENDED = 2; + +/* + The event system uses a series of nested hashes to store listeners on an + object. When a listener is registered, or when an event arrives, these + hashes are consulted to determine which target and action pair to invoke. + + The hashes are stored in the object's meta hash, and look like this: + + // Object's meta hash + { + listeners: { // variable name: `listenerSet` + "foo:changed": [ // variable name: `actions` + target, method, flags + ] + } + } + +*/ + +function indexOf(array, target, method) { + var index = -1; + for (var i = 0, l = array.length; i < l; i += 3) { + if (target === array[i] && method === array[i+1]) { index = i; break; } + } + return index; +} + +function actionsFor(obj, eventName) { + var meta = metaFor(obj, true), + actions; + + if (!meta.listeners) { meta.listeners = {}; } + + if (!meta.hasOwnProperty('listeners')) { + // setup inherited copy of the listeners object + meta.listeners = o_create(meta.listeners); + } + + actions = meta.listeners[eventName]; + + // if there are actions, but the eventName doesn't exist in our listeners, then copy them from the prototype + if (actions && !meta.listeners.hasOwnProperty(eventName)) { + actions = meta.listeners[eventName] = meta.listeners[eventName].slice(); + } else if (!actions) { + actions = meta.listeners[eventName] = []; + } + + return actions; +} + +function actionsUnion(obj, eventName, otherActions) { + var meta = obj[META_KEY], + actions = meta && meta.listeners && meta.listeners[eventName]; + + if (!actions) { return; } + for (var i = actions.length - 3; i >= 0; i -= 3) { + var target = actions[i], + method = actions[i+1], + flags = actions[i+2], + actionIndex = indexOf(otherActions, target, method); + + if (actionIndex === -1) { + otherActions.push(target, method, flags); + } + } +} + +function actionsDiff(obj, eventName, otherActions) { + var meta = obj[META_KEY], + actions = meta && meta.listeners && meta.listeners[eventName], + diffActions = []; + + if (!actions) { return; } + for (var i = actions.length - 3; i >= 0; i -= 3) { + var target = actions[i], + method = actions[i+1], + flags = actions[i+2], + actionIndex = indexOf(otherActions, target, method); + + if (actionIndex !== -1) { continue; } + + otherActions.push(target, method, flags); + diffActions.push(target, method, flags); + } + + return diffActions; +} + +/** + Add an event listener + + @method addListener + @for Ember + @param obj + @param {String} eventName + @param {Object|Function} targetOrMethod A target object or a function + @param {Function|String} method A function or the name of a function to be called on `target` + @param {Boolean} once A flag whether a function should only be called once +*/ +function addListener(obj, eventName, target, method, once) { + Ember.assert("You must pass at least an object and event name to Ember.addListener", !!obj && !!eventName); + + if (!method && 'function' === typeof target) { + method = target; + target = null; + } + + var actions = actionsFor(obj, eventName), + actionIndex = indexOf(actions, target, method), + flags = 0; + + if (once) flags |= ONCE; + + if (actionIndex !== -1) { return; } + + actions.push(target, method, flags); + + if ('function' === typeof obj.didAddListener) { + obj.didAddListener(eventName, target, method); + } +} + +/** + Remove an event listener + + Arguments should match those passed to `Ember.addListener`. + + @method removeListener + @for Ember + @param obj + @param {String} eventName + @param {Object|Function} targetOrMethod A target object or a function + @param {Function|String} method A function or the name of a function to be called on `target` +*/ +function removeListener(obj, eventName, target, method) { + Ember.assert("You must pass at least an object and event name to Ember.removeListener", !!obj && !!eventName); + + if (!method && 'function' === typeof target) { + method = target; + target = null; + } + + function _removeListener(target, method) { + var actions = actionsFor(obj, eventName), + actionIndex = indexOf(actions, target, method); + + // action doesn't exist, give up silently + if (actionIndex === -1) { return; } + + actions.splice(actionIndex, 3); + + if ('function' === typeof obj.didRemoveListener) { + obj.didRemoveListener(eventName, target, method); + } + } + + if (method) { + _removeListener(target, method); + } else { + var meta = obj[META_KEY], + actions = meta && meta.listeners && meta.listeners[eventName]; + + if (!actions) { return; } + for (var i = actions.length - 3; i >= 0; i -= 3) { + _removeListener(actions[i], actions[i+1]); + } + } +} + +/** + @private + + Suspend listener during callback. + + This should only be used by the target of the event listener + when it is taking an action that would cause the event, e.g. + an object might suspend its property change listener while it is + setting that property. + + @method suspendListener + @for Ember + @param obj + @param {String} eventName + @param {Object|Function} targetOrMethod A target object or a function + @param {Function|String} method A function or the name of a function to be called on `target` + @param {Function} callback +*/ +function suspendListener(obj, eventName, target, method, callback) { + if (!method && 'function' === typeof target) { + method = target; + target = null; + } + + var actions = actionsFor(obj, eventName), + actionIndex = indexOf(actions, target, method); + + if (actionIndex !== -1) { + actions[actionIndex+2] |= SUSPENDED; // mark the action as suspended + } + + function tryable() { return callback.call(target); } + function finalizer() { if (actionIndex !== -1) { actions[actionIndex+2] &= ~SUSPENDED; } } + + return Ember.tryFinally(tryable, finalizer); +} + +/** + @private + + Suspends multiple listeners during a callback. + + + @method suspendListeners + @for Ember + @param obj + @param {Array} eventName Array of event names + @param {Object|Function} targetOrMethod A target object or a function + @param {Function|String} method A function or the name of a function to be called on `target` + @param {Function} callback +*/ +function suspendListeners(obj, eventNames, target, method, callback) { + if (!method && 'function' === typeof target) { + method = target; + target = null; + } + + var suspendedActions = [], + actionsList = [], + eventName, actions, i, l; + + for (i=0, l=eventNames.length; i= 0; i -= 3) { // looping in reverse for once listeners + var target = actions[i], method = actions[i+1], flags = actions[i+2]; + if (!method) { continue; } + if (flags & SUSPENDED) { continue; } + if (flags & ONCE) { removeListener(obj, eventName, target, method); } + if (!target) { target = obj; } + if ('string' === typeof method) { method = target[method]; } + if (params) { + method.apply(target, params); + } else { + method.call(target); + } + } + return true; +} + +/** + @private + @method hasListeners + @for Ember + @param obj + @param {String} eventName +*/ +function hasListeners(obj, eventName) { + var meta = obj[META_KEY], + actions = meta && meta.listeners && meta.listeners[eventName]; + + return !!(actions && actions.length); +} + +/** + @private + @method listenersFor + @for Ember + @param obj + @param {String} eventName +*/ +function listenersFor(obj, eventName) { + var ret = []; + var meta = obj[META_KEY], + actions = meta && meta.listeners && meta.listeners[eventName]; + + if (!actions) { return ret; } + + for (var i = 0, l = actions.length; i < l; i += 3) { + var target = actions[i], + method = actions[i+1]; + ret.push([target, method]); + } + + return ret; +} + +/** + Define a property as a function that should be executed when + a specified event or events are triggered. + + var Job = Ember.Object.extend({ + logCompleted: Ember.on('completed', function(){ + console.log('Job completed!'); + }) + }); + var job = Job.create(); + Ember.sendEvent(job, 'completed'); // Logs "Job completed!" + + @method on + @for Ember + @param {String} eventNames* + @param {Function} func + @return func +*/ +Ember.on = function(){ + var func = a_slice.call(arguments, -1)[0], + events = a_slice.call(arguments, 0, -1); + func.__ember_listens__ = events; + return func; +}; + +Ember.addListener = addListener; +Ember.removeListener = removeListener; +Ember._suspendListener = suspendListener; +Ember._suspendListeners = suspendListeners; +Ember.sendEvent = sendEvent; +Ember.hasListeners = hasListeners; +Ember.watchedEvents = watchedEvents; +Ember.listenersFor = listenersFor; +Ember.listenersDiff = actionsDiff; +Ember.listenersUnion = actionsUnion; + +})(); + + + +(function() { +var guidFor = Ember.guidFor, + sendEvent = Ember.sendEvent; + +/* + this.observerSet = { + [senderGuid]: { // variable name: `keySet` + [keyName]: listIndex + } + }, + this.observers = [ + { + sender: obj, + keyName: keyName, + eventName: eventName, + listeners: [ + [target, method, flags] + ] + }, + ... + ] +*/ +var ObserverSet = Ember._ObserverSet = function() { + this.clear(); +}; + +ObserverSet.prototype.add = function(sender, keyName, eventName) { + var observerSet = this.observerSet, + observers = this.observers, + senderGuid = guidFor(sender), + keySet = observerSet[senderGuid], + index; + + if (!keySet) { + observerSet[senderGuid] = keySet = {}; + } + index = keySet[keyName]; + if (index === undefined) { + index = observers.push({ + sender: sender, + keyName: keyName, + eventName: eventName, + listeners: [] + }) - 1; + keySet[keyName] = index; + } + return observers[index].listeners; +}; + +ObserverSet.prototype.flush = function() { + var observers = this.observers, i, len, observer, sender; + this.clear(); + for (i=0, len=observers.length; i < len; ++i) { + observer = observers[i]; + sender = observer.sender; + if (sender.isDestroying || sender.isDestroyed) { continue; } + sendEvent(sender, observer.eventName, [sender, observer.keyName], observer.listeners); + } +}; + +ObserverSet.prototype.clear = function() { + this.observerSet = {}; + this.observers = []; +}; +})(); + + + +(function() { +var metaFor = Ember.meta, + guidFor = Ember.guidFor, + tryFinally = Ember.tryFinally, + sendEvent = Ember.sendEvent, + listenersUnion = Ember.listenersUnion, + listenersDiff = Ember.listenersDiff, + ObserverSet = Ember._ObserverSet, + beforeObserverSet = new ObserverSet(), + observerSet = new ObserverSet(), + deferred = 0; + +// .......................................................... +// PROPERTY CHANGES +// + +/** + This function is called just before an object property is about to change. + It will notify any before observers and prepare caches among other things. + + Normally you will not need to call this method directly but if for some + reason you can't directly watch a property you can invoke this method + manually along with `Ember.propertyDidChange()` which you should call just + after the property value changes. + + @method propertyWillChange + @for Ember + @param {Object} obj The object with the property that will change + @param {String} keyName The property key (or path) that will change. + @return {void} +*/ +function propertyWillChange(obj, keyName) { + var m = metaFor(obj, false), + watching = m.watching[keyName] > 0 || keyName === 'length', + proto = m.proto, + desc = m.descs[keyName]; + + if (!watching) { return; } + if (proto === obj) { return; } + if (desc && desc.willChange) { desc.willChange(obj, keyName); } + dependentKeysWillChange(obj, keyName, m); + chainsWillChange(obj, keyName, m); + notifyBeforeObservers(obj, keyName); +} +Ember.propertyWillChange = propertyWillChange; + +/** + This function is called just after an object property has changed. + It will notify any observers and clear caches among other things. + + Normally you will not need to call this method directly but if for some + reason you can't directly watch a property you can invoke this method + manually along with `Ember.propertyWillChange()` which you should call just + before the property value changes. + + @method propertyDidChange + @for Ember + @param {Object} obj The object with the property that will change + @param {String} keyName The property key (or path) that will change. + @return {void} +*/ +function propertyDidChange(obj, keyName) { + var m = metaFor(obj, false), + watching = m.watching[keyName] > 0 || keyName === 'length', + proto = m.proto, + desc = m.descs[keyName]; + + if (proto === obj) { return; } + + // shouldn't this mean that we're watching this key? + if (desc && desc.didChange) { desc.didChange(obj, keyName); } + if (!watching && keyName !== 'length') { return; } + + dependentKeysDidChange(obj, keyName, m); + chainsDidChange(obj, keyName, m, false); + notifyObservers(obj, keyName); +} +Ember.propertyDidChange = propertyDidChange; + +var WILL_SEEN, DID_SEEN; + +// called whenever a property is about to change to clear the cache of any dependent keys (and notify those properties of changes, etc...) +function dependentKeysWillChange(obj, depKey, meta) { + if (obj.isDestroying) { return; } + + var seen = WILL_SEEN, top = !seen; + if (top) { seen = WILL_SEEN = {}; } + iterDeps(propertyWillChange, obj, depKey, seen, meta); + if (top) { WILL_SEEN = null; } +} + +// called whenever a property has just changed to update dependent keys +function dependentKeysDidChange(obj, depKey, meta) { + if (obj.isDestroying) { return; } + + var seen = DID_SEEN, top = !seen; + if (top) { seen = DID_SEEN = {}; } + iterDeps(propertyDidChange, obj, depKey, seen, meta); + if (top) { DID_SEEN = null; } +} + +function iterDeps(method, obj, depKey, seen, meta) { + var guid = guidFor(obj); + if (!seen[guid]) seen[guid] = {}; + if (seen[guid][depKey]) return; + seen[guid][depKey] = true; + + var deps = meta.deps; + deps = deps && deps[depKey]; + if (deps) { + for(var key in deps) { + var desc = meta.descs[key]; + if (desc && desc._suspended === obj) continue; + method(obj, key); + } + } +} + +function chainsWillChange(obj, keyName, m) { + if (!(m.hasOwnProperty('chainWatchers') && + m.chainWatchers[keyName])) { + return; + } + + var nodes = m.chainWatchers[keyName], + events = [], + i, l; + + for(i = 0, l = nodes.length; i < l; i++) { + nodes[i].willChange(events); + } + + for (i = 0, l = events.length; i < l; i += 2) { + propertyWillChange(events[i], events[i+1]); + } +} + +function chainsDidChange(obj, keyName, m, suppressEvents) { + if (!(m.hasOwnProperty('chainWatchers') && + m.chainWatchers[keyName])) { + return; + } + + var nodes = m.chainWatchers[keyName], + events = suppressEvents ? null : [], + i, l; + + for(i = 0, l = nodes.length; i < l; i++) { + nodes[i].didChange(events); + } + + if (suppressEvents) { + return; + } + + for (i = 0, l = events.length; i < l; i += 2) { + propertyDidChange(events[i], events[i+1]); + } +} + +Ember.overrideChains = function(obj, keyName, m) { + chainsDidChange(obj, keyName, m, true); +}; + +/** + @method beginPropertyChanges + @chainable + @private +*/ +function beginPropertyChanges() { + deferred++; +} + +Ember.beginPropertyChanges = beginPropertyChanges; + +/** + @method endPropertyChanges + @private +*/ +function endPropertyChanges() { + deferred--; + if (deferred<=0) { + beforeObserverSet.clear(); + observerSet.flush(); + } +} + +Ember.endPropertyChanges = endPropertyChanges; + +/** + Make a series of property changes together in an + exception-safe way. + + ```javascript + Ember.changeProperties(function() { + obj1.set('foo', mayBlowUpWhenSet); + obj2.set('bar', baz); + }); + ``` + + @method changeProperties + @param {Function} callback + @param [binding] +*/ +Ember.changeProperties = function(cb, binding) { + beginPropertyChanges(); + tryFinally(cb, endPropertyChanges, binding); +}; + +function notifyBeforeObservers(obj, keyName) { + if (obj.isDestroying) { return; } + + var eventName = keyName + ':before', listeners, diff; + if (deferred) { + listeners = beforeObserverSet.add(obj, keyName, eventName); + diff = listenersDiff(obj, eventName, listeners); + sendEvent(obj, eventName, [obj, keyName], diff); + } else { + sendEvent(obj, eventName, [obj, keyName]); + } +} + +function notifyObservers(obj, keyName) { + if (obj.isDestroying) { return; } + + var eventName = keyName + ':change', listeners; + if (deferred) { + listeners = observerSet.add(obj, keyName, eventName); + listenersUnion(obj, eventName, listeners); + } else { + sendEvent(obj, eventName, [obj, keyName]); + } +} + +})(); + + + +(function() { +// META_KEY +// _getPath +// propertyWillChange, propertyDidChange + +var META_KEY = Ember.META_KEY, + MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER, + IS_GLOBAL = /^([A-Z$]|([0-9][A-Z$]))/, + getPath = Ember._getPath; + +/** + Sets the value of a property on an object, respecting computed properties + and notifying observers and other listeners of the change. If the + property is not defined but the object implements the `setUnknownProperty` + method then that will be invoked as well. + + If you plan to run on IE8 and older browsers then you should use this + method anytime you want to set a property on an object that you don't + know for sure is private. (Properties beginning with an underscore '_' + are considered private.) + + On all newer browsers, you only need to use this method to set + properties if the property might not be defined on the object and you want + to respect the `setUnknownProperty` handler. Otherwise you can ignore this + method. + + @method set + @for Ember + @param {Object} obj The object to modify. + @param {String} keyName The property key to set + @param {Object} value The value to set + @return {Object} the passed value. +*/ +var set = function set(obj, keyName, value, tolerant) { + if (typeof obj === 'string') { + Ember.assert("Path '" + obj + "' must be global if no obj is given.", IS_GLOBAL.test(obj)); + value = keyName; + keyName = obj; + obj = null; + } + + Ember.assert("Cannot call set with "+ keyName +" key.", !!keyName); + + if (!obj || keyName.indexOf('.') !== -1) { + return setPath(obj, keyName, value, tolerant); + } + + Ember.assert("You need to provide an object and key to `set`.", !!obj && keyName !== undefined); + Ember.assert('calling set on destroyed object', !obj.isDestroyed); + + var meta = obj[META_KEY], desc = meta && meta.descs[keyName], + isUnknown, currentValue; + if (desc) { + desc.set(obj, keyName, value); + } else { + isUnknown = 'object' === typeof obj && !(keyName in obj); + + // setUnknownProperty is called if `obj` is an object, + // the property does not already exist, and the + // `setUnknownProperty` method exists on the object + if (isUnknown && 'function' === typeof obj.setUnknownProperty) { + obj.setUnknownProperty(keyName, value); + } else if (meta && meta.watching[keyName] > 0) { + if (MANDATORY_SETTER) { + currentValue = meta.values[keyName]; + } else { + currentValue = obj[keyName]; + } + // only trigger a change if the value has changed + if (value !== currentValue) { + Ember.propertyWillChange(obj, keyName); + if (MANDATORY_SETTER) { + if (currentValue === undefined && !(keyName in obj)) { + Ember.defineProperty(obj, keyName, null, value); // setup mandatory setter + } else { + meta.values[keyName] = value; + } + } else { + obj[keyName] = value; + } + Ember.propertyDidChange(obj, keyName); + } + } else { + obj[keyName] = value; + } + } + return value; +}; + +// Currently used only by Ember Data tests +if (Ember.config.overrideAccessors) { + Ember.set = set; + Ember.config.overrideAccessors(); + set = Ember.set; +} + +function setPath(root, path, value, tolerant) { + var keyName; + + // get the last part of the path + keyName = path.slice(path.lastIndexOf('.') + 1); + + // get the first part of the part + path = path.slice(0, path.length-(keyName.length+1)); + + // unless the path is this, look up the first part to + // get the root + if (path !== 'this') { + root = getPath(root, path); + } + + if (!keyName || keyName.length === 0) { + throw new Ember.Error('You passed an empty path'); + } + + if (!root) { + if (tolerant) { return; } + else { throw new Ember.Error('Object in path '+path+' could not be found or was destroyed.'); } + } + + return set(root, keyName, value); +} + +Ember.set = set; + +/** + Error-tolerant form of `Ember.set`. Will not blow up if any part of the + chain is `undefined`, `null`, or destroyed. + + This is primarily used when syncing bindings, which may try to update after + an object has been destroyed. + + @method trySet + @for Ember + @param {Object} obj The object to modify. + @param {String} path The property path to set + @param {Object} value The value to set +*/ +Ember.trySet = function(root, path, value) { + return set(root, path, value, true); +}; + +})(); + + + +(function() { +/** +@module ember-metal +*/ + +/* + JavaScript (before ES6) does not have a Map implementation. Objects, + which are often used as dictionaries, may only have Strings as keys. + + Because Ember has a way to get a unique identifier for every object + via `Ember.guidFor`, we can implement a performant Map with arbitrary + keys. Because it is commonly used in low-level bookkeeping, Map is + implemented as a pure JavaScript object for performance. + + This implementation follows the current iteration of the ES6 proposal for + maps (http://wiki.ecmascript.org/doku.php?id=harmony:simple_maps_and_sets), + with two exceptions. First, because we need our implementation to be pleasant + on older browsers, we do not use the `delete` name (using `remove` instead). + Second, as we do not have the luxury of in-VM iteration, we implement a + forEach method for iteration. + + Map is mocked out to look like an Ember object, so you can do + `Ember.Map.create()` for symmetry with other Ember classes. +*/ +var set = Ember.set, + guidFor = Ember.guidFor, + indexOf = Ember.ArrayPolyfills.indexOf; + +var copy = function(obj) { + var output = {}; + + for (var prop in obj) { + if (obj.hasOwnProperty(prop)) { output[prop] = obj[prop]; } + } + + return output; +}; + +var copyMap = function(original, newObject) { + var keys = original.keys.copy(), + values = copy(original.values); + + newObject.keys = keys; + newObject.values = values; + newObject.length = original.length; + + return newObject; +}; + +/** + This class is used internally by Ember and Ember Data. + Please do not use it at this time. We plan to clean it up + and add many tests soon. + + @class OrderedSet + @namespace Ember + @constructor + @private +*/ +var OrderedSet = Ember.OrderedSet = function() { + this.clear(); +}; + +/** + @method create + @static + @return {Ember.OrderedSet} +*/ +OrderedSet.create = function() { + return new OrderedSet(); +}; + + +OrderedSet.prototype = { + /** + @method clear + */ + clear: function() { + this.presenceSet = {}; + this.list = []; + }, + + /** + @method add + @param obj + */ + add: function(obj) { + var guid = guidFor(obj), + presenceSet = this.presenceSet, + list = this.list; + + if (guid in presenceSet) { return; } + + presenceSet[guid] = true; + list.push(obj); + }, + + /** + @method remove + @param obj + */ + remove: function(obj) { + var guid = guidFor(obj), + presenceSet = this.presenceSet, + list = this.list; + + delete presenceSet[guid]; + + var index = indexOf.call(list, obj); + if (index > -1) { + list.splice(index, 1); + } + }, + + /** + @method isEmpty + @return {Boolean} + */ + isEmpty: function() { + return this.list.length === 0; + }, + + /** + @method has + @param obj + @return {Boolean} + */ + has: function(obj) { + var guid = guidFor(obj), + presenceSet = this.presenceSet; + + return guid in presenceSet; + }, + + /** + @method forEach + @param {Function} fn + @param self + */ + forEach: function(fn, self) { + // allow mutation during iteration + var list = this.toArray(); + + for (var i = 0, j = list.length; i < j; i++) { + fn.call(self, list[i]); + } + }, + + /** + @method toArray + @return {Array} + */ + toArray: function() { + return this.list.slice(); + }, + + /** + @method copy + @return {Ember.OrderedSet} + */ + copy: function() { + var set = new OrderedSet(); + + set.presenceSet = copy(this.presenceSet); + set.list = this.toArray(); + + return set; + } +}; + +/** + A Map stores values indexed by keys. Unlike JavaScript's + default Objects, the keys of a Map can be any JavaScript + object. + + Internally, a Map has two data structures: + + 1. `keys`: an OrderedSet of all of the existing keys + 2. `values`: a JavaScript Object indexed by the `Ember.guidFor(key)` + + When a key/value pair is added for the first time, we + add the key to the `keys` OrderedSet, and create or + replace an entry in `values`. When an entry is deleted, + we delete its entry in `keys` and `values`. + + @class Map + @namespace Ember + @private + @constructor +*/ +var Map = Ember.Map = function() { + this.keys = Ember.OrderedSet.create(); + this.values = {}; +}; + +/** + @method create + @static +*/ +Map.create = function() { + return new Map(); +}; + +Map.prototype = { + /** + This property will change as the number of objects in the map changes. + + @property length + @type number + @default 0 + */ + length: 0, + + + /** + Retrieve the value associated with a given key. + + @method get + @param {*} key + @return {*} the value associated with the key, or `undefined` + */ + get: function(key) { + var values = this.values, + guid = guidFor(key); + + return values[guid]; + }, + + /** + Adds a value to the map. If a value for the given key has already been + provided, the new value will replace the old value. + + @method set + @param {*} key + @param {*} value + */ + set: function(key, value) { + var keys = this.keys, + values = this.values, + guid = guidFor(key); + + keys.add(key); + values[guid] = value; + set(this, 'length', keys.list.length); + }, + + /** + Removes a value from the map for an associated key. + + @method remove + @param {*} key + @return {Boolean} true if an item was removed, false otherwise + */ + remove: function(key) { + // don't use ES6 "delete" because it will be annoying + // to use in browsers that are not ES6 friendly; + var keys = this.keys, + values = this.values, + guid = guidFor(key); + + if (values.hasOwnProperty(guid)) { + keys.remove(key); + delete values[guid]; + set(this, 'length', keys.list.length); + return true; + } else { + return false; + } + }, + + /** + Check whether a key is present. + + @method has + @param {*} key + @return {Boolean} true if the item was present, false otherwise + */ + has: function(key) { + var values = this.values, + guid = guidFor(key); + + return values.hasOwnProperty(guid); + }, + + /** + Iterate over all the keys and values. Calls the function once + for each key, passing in the key and value, in that order. + + The keys are guaranteed to be iterated over in insertion order. + + @method forEach + @param {Function} callback + @param {*} self if passed, the `this` value inside the + callback. By default, `this` is the map. + */ + forEach: function(callback, self) { + var keys = this.keys, + values = this.values; + + keys.forEach(function(key) { + var guid = guidFor(key); + callback.call(self, key, values[guid]); + }); + }, + + /** + @method copy + @return {Ember.Map} + */ + copy: function() { + return copyMap(this, new Map()); + } +}; + +/** + @class MapWithDefault + @namespace Ember + @extends Ember.Map + @private + @constructor + @param [options] + @param {*} [options.defaultValue] +*/ +var MapWithDefault = Ember.MapWithDefault = function(options) { + Map.call(this); + this.defaultValue = options.defaultValue; +}; + +/** + @method create + @static + @param [options] + @param {*} [options.defaultValue] + @return {Ember.MapWithDefault|Ember.Map} If options are passed, returns + `Ember.MapWithDefault` otherwise returns `Ember.Map` +*/ +MapWithDefault.create = function(options) { + if (options) { + return new MapWithDefault(options); + } else { + return new Map(); + } +}; + +MapWithDefault.prototype = Ember.create(Map.prototype); + +/** + Retrieve the value associated with a given key. + + @method get + @param {*} key + @return {*} the value associated with the key, or the default value +*/ +MapWithDefault.prototype.get = function(key) { + var hasValue = this.has(key); + + if (hasValue) { + return Map.prototype.get.call(this, key); + } else { + var defaultValue = this.defaultValue(key); + this.set(key, defaultValue); + return defaultValue; + } +}; + +/** + @method copy + @return {Ember.MapWithDefault} +*/ +MapWithDefault.prototype.copy = function() { + return copyMap(this, new MapWithDefault({ + defaultValue: this.defaultValue + })); +}; + +})(); + + + +(function() { +function consoleMethod(name) { + var consoleObj; + if (Ember.imports.console) { + consoleObj = Ember.imports.console; + } else if (typeof console !== 'undefined') { + consoleObj = console; + } + + var method = typeof consoleObj === 'object' ? consoleObj[name] : null; + + if (method) { + // Older IE doesn't support apply, but Chrome needs it + if (method.apply) { + return function() { + method.apply(consoleObj, arguments); + }; + } else { + return function() { + var message = Array.prototype.join.call(arguments, ', '); + method(message); + }; + } + } +} + +function assertPolyfill(test, message) { + if (!test) { + try { + // attempt to preserve the stack + throw new Ember.Error("assertion failed: " + message); + } catch(error) { + setTimeout(function() { + throw error; + }, 0); + } + } +} + +/** + Inside Ember-Metal, simply uses the methods from `imports.console`. + Override this to provide more robust logging functionality. + + @class Logger + @namespace Ember +*/ +Ember.Logger = { + /** + Logs the arguments to the console. + You can pass as many arguments as you want and they will be joined together with a space. + + ```javascript + var foo = 1; + Ember.Logger.log('log value of foo:', foo); // "log value of foo: 1" will be printed to the console + ``` + + @method log + @for Ember.Logger + @param {*} arguments + */ + log: consoleMethod('log') || Ember.K, + /** + Prints the arguments to the console with a warning icon. + You can pass as many arguments as you want and they will be joined together with a space. + + ```javascript + Ember.Logger.warn('Something happened!'); // "Something happened!" will be printed to the console with a warning icon. + ``` + + @method warn + @for Ember.Logger + @param {*} arguments + */ + warn: consoleMethod('warn') || Ember.K, + /** + Prints the arguments to the console with an error icon, red text and a stack race. + You can pass as many arguments as you want and they will be joined together with a space. + + ```javascript + Ember.Logger.error('Danger! Danger!'); // "Danger! Danger!" will be printed to the console in red text. + ``` + + @method error + @for Ember.Logger + @param {*} arguments + */ + error: consoleMethod('error') || Ember.K, + /** + Logs the arguments to the console. + You can pass as many arguments as you want and they will be joined together with a space. + + ```javascript + var foo = 1; + Ember.Logger.info('log value of foo:', foo); // "log value of foo: 1" will be printed to the console + ``` + + @method info + @for Ember.Logger + @param {*} arguments + */ + info: consoleMethod('info') || Ember.K, + /** + Logs the arguments to the console in blue text. + You can pass as many arguments as you want and they will be joined together with a space. + + ```javascript + var foo = 1; + Ember.Logger.debug('log value of foo:', foo); // "log value of foo: 1" will be printed to the console + ``` + + @method debug + @for Ember.Logger + @param {*} arguments + */ + debug: consoleMethod('debug') || consoleMethod('info') || Ember.K, + /** + + If the value passed into Ember.Logger.assert is not truthy it will throw an error with a stack trace. + + ```javascript + Ember.Logger.assert(true); // undefined + Ember.Logger.assert(true === false); // Throws an Assertion failed error. + ``` + + @method assert + @for Ember.Logger + @param {Boolean} bool Value to test + */ + assert: consoleMethod('assert') || assertPolyfill +}; + + +})(); + + + +(function() { +/** +@module ember-metal +*/ + +var META_KEY = Ember.META_KEY, + metaFor = Ember.meta, + objectDefineProperty = Ember.platform.defineProperty; + +var MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER; + +// .......................................................... +// DESCRIPTOR +// + +/** + Objects of this type can implement an interface to respond to requests to + get and set. The default implementation handles simple properties. + + You generally won't need to create or subclass this directly. + + @class Descriptor + @namespace Ember + @private + @constructor +*/ +Ember.Descriptor = function() {}; + +// .......................................................... +// DEFINING PROPERTIES API +// + +var MANDATORY_SETTER_FUNCTION = Ember.MANDATORY_SETTER_FUNCTION = function(value) { + Ember.assert("You must use Ember.set() to access this property (of " + this + ")", false); +}; + +var DEFAULT_GETTER_FUNCTION = Ember.DEFAULT_GETTER_FUNCTION = function(name) { + return function() { + var meta = this[META_KEY]; + return meta && meta.values[name]; + }; +}; + +/** + @private + + NOTE: This is a low-level method used by other parts of the API. You almost + never want to call this method directly. Instead you should use + `Ember.mixin()` to define new properties. + + Defines a property on an object. This method works much like the ES5 + `Object.defineProperty()` method except that it can also accept computed + properties and other special descriptors. + + Normally this method takes only three parameters. However if you pass an + instance of `Ember.Descriptor` as the third param then you can pass an + optional value as the fourth parameter. This is often more efficient than + creating new descriptor hashes for each property. + + ## Examples + + ```javascript + // ES5 compatible mode + Ember.defineProperty(contact, 'firstName', { + writable: true, + configurable: false, + enumerable: true, + value: 'Charles' + }); + + // define a simple property + Ember.defineProperty(contact, 'lastName', undefined, 'Jolley'); + + // define a computed property + Ember.defineProperty(contact, 'fullName', Ember.computed(function() { + return this.firstName+' '+this.lastName; + }).property('firstName', 'lastName')); + ``` + + @method defineProperty + @for Ember + @param {Object} obj the object to define this property on. This may be a prototype. + @param {String} keyName the name of the property + @param {Ember.Descriptor} [desc] an instance of `Ember.Descriptor` (typically a + computed property) or an ES5 descriptor. + You must provide this or `data` but not both. + @param {*} [data] something other than a descriptor, that will + become the explicit value of this property. +*/ +Ember.defineProperty = function(obj, keyName, desc, data, meta) { + var descs, existingDesc, watching, value; + + if (!meta) meta = metaFor(obj); + descs = meta.descs; + existingDesc = meta.descs[keyName]; + watching = meta.watching[keyName] > 0; + + if (existingDesc instanceof Ember.Descriptor) { + existingDesc.teardown(obj, keyName); + } + + if (desc instanceof Ember.Descriptor) { + value = desc; + + descs[keyName] = desc; + if (MANDATORY_SETTER && watching) { + objectDefineProperty(obj, keyName, { + configurable: true, + enumerable: true, + writable: true, + value: undefined // make enumerable + }); + } else { + obj[keyName] = undefined; // make enumerable + } + } else { + descs[keyName] = undefined; // shadow descriptor in proto + if (desc == null) { + value = data; + + if (MANDATORY_SETTER && watching) { + meta.values[keyName] = data; + objectDefineProperty(obj, keyName, { + configurable: true, + enumerable: true, + set: MANDATORY_SETTER_FUNCTION, + get: DEFAULT_GETTER_FUNCTION(keyName) + }); + } else { + obj[keyName] = data; + } + } else { + value = desc; + + // compatibility with ES5 + objectDefineProperty(obj, keyName, desc); + } + } + + // if key is being watched, override chains that + // were initialized with the prototype + if (watching) { Ember.overrideChains(obj, keyName, meta); } + + // The `value` passed to the `didDefineProperty` hook is + // either the descriptor or data, whichever was passed. + if (obj.didDefineProperty) { obj.didDefineProperty(obj, keyName, value); } + + return this; +}; + + +})(); + + + +(function() { +var get = Ember.get; + +/** + To get multiple properties at once, call `Ember.getProperties` + with an object followed by a list of strings or an array: + + ```javascript + Ember.getProperties(record, 'firstName', 'lastName', 'zipCode'); // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } + ``` + + is equivalent to: + + ```javascript + Ember.getProperties(record, ['firstName', 'lastName', 'zipCode']); // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } + ``` + + @method getProperties + @param obj + @param {String...|Array} list of keys to get + @return {Hash} +*/ +Ember.getProperties = function(obj) { + var ret = {}, + propertyNames = arguments, + i = 1; + + if (arguments.length === 2 && Ember.typeOf(arguments[1]) === 'array') { + i = 0; + propertyNames = arguments[1]; + } + for(var len = propertyNames.length; i < len; i++) { + ret[propertyNames[i]] = get(obj, propertyNames[i]); + } + return ret; +}; + +})(); + + + +(function() { +var changeProperties = Ember.changeProperties, + set = Ember.set; + +/** + Set a list of properties on an object. These properties are set inside + a single `beginPropertyChanges` and `endPropertyChanges` batch, so + observers will be buffered. + + ```javascript + anObject.setProperties({ + firstName: "Stanley", + lastName: "Stuart", + age: "21" + }) + ``` + + @method setProperties + @param self + @param {Object} hash + @return self +*/ +Ember.setProperties = function(self, hash) { + changeProperties(function() { + for(var prop in hash) { + if (hash.hasOwnProperty(prop)) { set(self, prop, hash[prop]); } + } + }); + return self; +}; + +})(); + + + +(function() { +var metaFor = Ember.meta, // utils.js + typeOf = Ember.typeOf, // utils.js + MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER, + o_defineProperty = Ember.platform.defineProperty; + +Ember.watchKey = function(obj, keyName) { + // can't watch length on Array - it is special... + if (keyName === 'length' && typeOf(obj) === 'array') { return; } + + var m = metaFor(obj), watching = m.watching; + + // activate watching first time + if (!watching[keyName]) { + watching[keyName] = 1; + + if ('function' === typeof obj.willWatchProperty) { + obj.willWatchProperty(keyName); + } + + if (MANDATORY_SETTER && keyName in obj) { + m.values[keyName] = obj[keyName]; + o_defineProperty(obj, keyName, { + configurable: true, + enumerable: true, + set: Ember.MANDATORY_SETTER_FUNCTION, + get: Ember.DEFAULT_GETTER_FUNCTION(keyName) + }); + } + } else { + watching[keyName] = (watching[keyName] || 0) + 1; + } +}; + + +Ember.unwatchKey = function(obj, keyName) { + var m = metaFor(obj), watching = m.watching; + + if (watching[keyName] === 1) { + watching[keyName] = 0; + + if ('function' === typeof obj.didUnwatchProperty) { + obj.didUnwatchProperty(keyName); + } + + if (MANDATORY_SETTER && keyName in obj) { + o_defineProperty(obj, keyName, { + configurable: true, + enumerable: true, + writable: true, + value: m.values[keyName] + }); + delete m.values[keyName]; + } + } else if (watching[keyName] > 1) { + watching[keyName]--; + } +}; + +})(); + + + +(function() { +var metaFor = Ember.meta, // utils.js + get = Ember.get, // property_get.js + normalizeTuple = Ember.normalizeTuple, // property_get.js + forEach = Ember.ArrayPolyfills.forEach, // array.js + warn = Ember.warn, + watchKey = Ember.watchKey, + unwatchKey = Ember.unwatchKey, + FIRST_KEY = /^([^\.\*]+)/; + +function firstKey(path) { + return path.match(FIRST_KEY)[0]; +} + +var pendingQueue = []; + +// attempts to add the pendingQueue chains again. If some of them end up +// back in the queue and reschedule is true, schedules a timeout to try +// again. +Ember.flushPendingChains = function() { + if (pendingQueue.length === 0) { return; } // nothing to do + + var queue = pendingQueue; + pendingQueue = []; + + forEach.call(queue, function(q) { q[0].add(q[1]); }); + + warn('Watching an undefined global, Ember expects watched globals to be setup by the time the run loop is flushed, check for typos', pendingQueue.length === 0); +}; + + +function addChainWatcher(obj, keyName, node) { + if (!obj || ('object' !== typeof obj)) { return; } // nothing to do + + var m = metaFor(obj), nodes = m.chainWatchers; + + if (!m.hasOwnProperty('chainWatchers')) { + nodes = m.chainWatchers = {}; + } + + if (!nodes[keyName]) { nodes[keyName] = []; } + nodes[keyName].push(node); + watchKey(obj, keyName); +} + +var removeChainWatcher = Ember.removeChainWatcher = function(obj, keyName, node) { + if (!obj || 'object' !== typeof obj) { return; } // nothing to do + + var m = metaFor(obj, false); + if (!m.hasOwnProperty('chainWatchers')) { return; } // nothing to do + + var nodes = m.chainWatchers; + + if (nodes[keyName]) { + nodes = nodes[keyName]; + for (var i = 0, l = nodes.length; i < l; i++) { + if (nodes[i] === node) { nodes.splice(i, 1); } + } + } + unwatchKey(obj, keyName); +}; + +// A ChainNode watches a single key on an object. If you provide a starting +// value for the key then the node won't actually watch it. For a root node +// pass null for parent and key and object for value. +var ChainNode = Ember._ChainNode = function(parent, key, value) { + this._parent = parent; + this._key = key; + + // _watching is true when calling get(this._parent, this._key) will + // return the value of this node. + // + // It is false for the root of a chain (because we have no parent) + // and for global paths (because the parent node is the object with + // the observer on it) + this._watching = value===undefined; + + this._value = value; + this._paths = {}; + if (this._watching) { + this._object = parent.value(); + if (this._object) { addChainWatcher(this._object, this._key, this); } + } + + // Special-case: the EachProxy relies on immediate evaluation to + // establish its observers. + // + // TODO: Replace this with an efficient callback that the EachProxy + // can implement. + if (this._parent && this._parent._key === '@each') { + this.value(); + } +}; + +var ChainNodePrototype = ChainNode.prototype; + +function lazyGet(obj, key) { + if (!obj) return undefined; + + var meta = metaFor(obj, false); + // check if object meant only to be a prototype + if (meta.proto === obj) return undefined; + + if (key === "@each") return get(obj, key); + + // if a CP only return cached value + var desc = meta.descs[key]; + if (desc && desc._cacheable) { + if (key in meta.cache) { + return meta.cache[key]; + } else { + return undefined; + } + } + + return get(obj, key); +} + +ChainNodePrototype.value = function() { + if (this._value === undefined && this._watching) { + var obj = this._parent.value(); + this._value = lazyGet(obj, this._key); + } + return this._value; +}; + +ChainNodePrototype.destroy = function() { + if (this._watching) { + var obj = this._object; + if (obj) { removeChainWatcher(obj, this._key, this); } + this._watching = false; // so future calls do nothing + } +}; + +// copies a top level object only +ChainNodePrototype.copy = function(obj) { + var ret = new ChainNode(null, null, obj), + paths = this._paths, path; + for (path in paths) { + if (paths[path] <= 0) { continue; } // this check will also catch non-number vals. + ret.add(path); + } + return ret; +}; + +// called on the root node of a chain to setup watchers on the specified +// path. +ChainNodePrototype.add = function(path) { + var obj, tuple, key, src, paths; + + paths = this._paths; + paths[path] = (paths[path] || 0) + 1; + + obj = this.value(); + tuple = normalizeTuple(obj, path); + + // the path was a local path + if (tuple[0] && tuple[0] === obj) { + path = tuple[1]; + key = firstKey(path); + path = path.slice(key.length+1); + + // global path, but object does not exist yet. + // put into a queue and try to connect later. + } else if (!tuple[0]) { + pendingQueue.push([this, path]); + tuple.length = 0; + return; + + // global path, and object already exists + } else { + src = tuple[0]; + key = path.slice(0, 0-(tuple[1].length+1)); + path = tuple[1]; + } + + tuple.length = 0; + this.chain(key, path, src); +}; + +// called on the root node of a chain to teardown watcher on the specified +// path +ChainNodePrototype.remove = function(path) { + var obj, tuple, key, src, paths; + + paths = this._paths; + if (paths[path] > 0) { paths[path]--; } + + obj = this.value(); + tuple = normalizeTuple(obj, path); + if (tuple[0] === obj) { + path = tuple[1]; + key = firstKey(path); + path = path.slice(key.length+1); + } else { + src = tuple[0]; + key = path.slice(0, 0-(tuple[1].length+1)); + path = tuple[1]; + } + + tuple.length = 0; + this.unchain(key, path); +}; + +ChainNodePrototype.count = 0; + +ChainNodePrototype.chain = function(key, path, src) { + var chains = this._chains, node; + if (!chains) { chains = this._chains = {}; } + + node = chains[key]; + if (!node) { node = chains[key] = new ChainNode(this, key, src); } + node.count++; // count chains... + + // chain rest of path if there is one + if (path && path.length>0) { + key = firstKey(path); + path = path.slice(key.length+1); + node.chain(key, path); // NOTE: no src means it will observe changes... + } +}; + +ChainNodePrototype.unchain = function(key, path) { + var chains = this._chains, node = chains[key]; + + // unchain rest of path first... + if (path && path.length>1) { + key = firstKey(path); + path = path.slice(key.length+1); + node.unchain(key, path); + } + + // delete node if needed. + node.count--; + if (node.count<=0) { + delete chains[node._key]; + node.destroy(); + } + +}; + +ChainNodePrototype.willChange = function(events) { + var chains = this._chains; + if (chains) { + for(var key in chains) { + if (!chains.hasOwnProperty(key)) { continue; } + chains[key].willChange(events); + } + } + + if (this._parent) { this._parent.chainWillChange(this, this._key, 1, events); } +}; + +ChainNodePrototype.chainWillChange = function(chain, path, depth, events) { + if (this._key) { path = this._key + '.' + path; } + + if (this._parent) { + this._parent.chainWillChange(this, path, depth+1, events); + } else { + if (depth > 1) { + events.push(this.value(), path); + } + path = 'this.' + path; + if (this._paths[path] > 0) { + events.push(this.value(), path); + } + } +}; + +ChainNodePrototype.chainDidChange = function(chain, path, depth, events) { + if (this._key) { path = this._key + '.' + path; } + if (this._parent) { + this._parent.chainDidChange(this, path, depth+1, events); + } else { + if (depth > 1) { + events.push(this.value(), path); + } + path = 'this.' + path; + if (this._paths[path] > 0) { + events.push(this.value(), path); + } + } +}; + +ChainNodePrototype.didChange = function(events) { + // invalidate my own value first. + if (this._watching) { + var obj = this._parent.value(); + if (obj !== this._object) { + removeChainWatcher(this._object, this._key, this); + this._object = obj; + addChainWatcher(obj, this._key, this); + } + this._value = undefined; + + // Special-case: the EachProxy relies on immediate evaluation to + // establish its observers. + if (this._parent && this._parent._key === '@each') + this.value(); + } + + // then notify chains... + var chains = this._chains; + if (chains) { + for(var key in chains) { + if (!chains.hasOwnProperty(key)) { continue; } + chains[key].didChange(events); + } + } + + // if no events are passed in then we only care about the above wiring update + if (events === null) { return; } + + // and finally tell parent about my path changing... + if (this._parent) { this._parent.chainDidChange(this, this._key, 1, events); } +}; + +Ember.finishChains = function(obj) { + var m = metaFor(obj, false), chains = m.chains; + if (chains) { + if (chains.value() !== obj) { + m.chains = chains = chains.copy(obj); + } + chains.didChange(null); + } +}; + +})(); + + + +(function() { +/** + @module ember-metal +*/ + + +})(); + + + +(function() { +var metaFor = Ember.meta, // utils.js + typeOf = Ember.typeOf, // utils.js + ChainNode = Ember._ChainNode; // chains.js + +// get the chains for the current object. If the current object has +// chains inherited from the proto they will be cloned and reconfigured for +// the current object. +function chainsFor(obj) { + var m = metaFor(obj), ret = m.chains; + if (!ret) { + ret = m.chains = new ChainNode(null, null, obj); + } else if (ret.value() !== obj) { + ret = m.chains = ret.copy(obj); + } + return ret; +} + +Ember.watchPath = function(obj, keyPath) { + // can't watch length on Array - it is special... + if (keyPath === 'length' && typeOf(obj) === 'array') { return; } + + var m = metaFor(obj), watching = m.watching; + + if (!watching[keyPath]) { // activate watching first time + watching[keyPath] = 1; + chainsFor(obj).add(keyPath); + } else { + watching[keyPath] = (watching[keyPath] || 0) + 1; + } +}; + +Ember.unwatchPath = function(obj, keyPath) { + var m = metaFor(obj), watching = m.watching; + + if (watching[keyPath] === 1) { + watching[keyPath] = 0; + chainsFor(obj).remove(keyPath); + } else if (watching[keyPath] > 1) { + watching[keyPath]--; + } +}; +})(); + + + +(function() { +/** +@module ember-metal +*/ + +var metaFor = Ember.meta, // utils.js + GUID_KEY = Ember.GUID_KEY, // utils.js + META_KEY = Ember.META_KEY, // utils.js + removeChainWatcher = Ember.removeChainWatcher, + watchKey = Ember.watchKey, // watch_key.js + unwatchKey = Ember.unwatchKey, + watchPath = Ember.watchPath, // watch_path.js + unwatchPath = Ember.unwatchPath, + typeOf = Ember.typeOf, // utils.js + generateGuid = Ember.generateGuid, + IS_PATH = /[\.\*]/; + + +// returns true if the passed path is just a keyName +function isKeyName(path) { + return path==='*' || !IS_PATH.test(path); +} + +/** + @private + + Starts watching a property on an object. Whenever the property changes, + invokes `Ember.propertyWillChange` and `Ember.propertyDidChange`. This is the + primitive used by observers and dependent keys; usually you will never call + this method directly but instead use higher level methods like + `Ember.addObserver()` + + @method watch + @for Ember + @param obj + @param {String} keyName +*/ +Ember.watch = function(obj, _keyPath) { + // can't watch length on Array - it is special... + if (_keyPath === 'length' && typeOf(obj) === 'array') { return; } + + + if (isKeyName(_keyPath)) { + watchKey(obj, _keyPath); + } else { + watchPath(obj, _keyPath); + } + +}; + +Ember.isWatching = function isWatching(obj, key) { + var meta = obj[META_KEY]; + return (meta && meta.watching[key]) > 0; +}; + +Ember.watch.flushPending = Ember.flushPendingChains; + +Ember.unwatch = function(obj, _keyPath) { + // can't watch length on Array - it is special... + if (_keyPath === 'length' && typeOf(obj) === 'array') { return; } + + + if (isKeyName(_keyPath)) { + unwatchKey(obj, _keyPath); + } else { + unwatchPath(obj, _keyPath); + } + +}; + +/** + @private + + Call on an object when you first beget it from another object. This will + setup any chained watchers on the object instance as needed. This method is + safe to call multiple times. + + @method rewatch + @for Ember + @param obj +*/ +Ember.rewatch = function(obj) { + var m = metaFor(obj, false), chains = m.chains; + + // make sure the object has its own guid. + if (GUID_KEY in obj && !obj.hasOwnProperty(GUID_KEY)) { + generateGuid(obj); + } + + // make sure any chained watchers update. + if (chains && chains.value() !== obj) { + m.chains = chains.copy(obj); + } +}; + +var NODE_STACK = []; + +/** + Tears down the meta on an object so that it can be garbage collected. + Multiple calls will have no effect. + + @method destroy + @for Ember + @param {Object} obj the object to destroy + @return {void} +*/ +Ember.destroy = function (obj) { + var meta = obj[META_KEY], node, nodes, key, nodeObject; + if (meta) { + obj[META_KEY] = null; + // remove chainWatchers to remove circular references that would prevent GC + node = meta.chains; + if (node) { + NODE_STACK.push(node); + // process tree + while (NODE_STACK.length > 0) { + node = NODE_STACK.pop(); + // push children + nodes = node._chains; + if (nodes) { + for (key in nodes) { + if (nodes.hasOwnProperty(key)) { + NODE_STACK.push(nodes[key]); + } + } + } + // remove chainWatcher in node object + if (node._watching) { + nodeObject = node._object; + if (nodeObject) { + removeChainWatcher(nodeObject, node._key, node); + } + } + } + } + } +}; + +})(); + + + +(function() { +/** +@module ember-metal +*/ + +Ember.warn("The CP_DEFAULT_CACHEABLE flag has been removed and computed properties are always cached by default. Use `volatile` if you don't want caching.", Ember.ENV.CP_DEFAULT_CACHEABLE !== false); + + +var get = Ember.get, + set = Ember.set, + metaFor = Ember.meta, + a_slice = [].slice, + o_create = Ember.create, + META_KEY = Ember.META_KEY, + watch = Ember.watch, + unwatch = Ember.unwatch; + + +// .......................................................... +// DEPENDENT KEYS +// + +// data structure: +// meta.deps = { +// 'depKey': { +// 'keyName': count, +// } +// } + +/* + This function returns a map of unique dependencies for a + given object and key. +*/ +function keysForDep(depsMeta, depKey) { + var keys = depsMeta[depKey]; + if (!keys) { + // if there are no dependencies yet for a the given key + // create a new empty list of dependencies for the key + keys = depsMeta[depKey] = {}; + } else if (!depsMeta.hasOwnProperty(depKey)) { + // otherwise if the dependency list is inherited from + // a superclass, clone the hash + keys = depsMeta[depKey] = o_create(keys); + } + return keys; +} + +function metaForDeps(meta) { + return keysForDep(meta, 'deps'); +} + +function addDependentKeys(desc, obj, keyName, meta) { + // the descriptor has a list of dependent keys, so + // add all of its dependent keys. + var depKeys = desc._dependentKeys, depsMeta, idx, len, depKey, keys; + if (!depKeys) return; + + depsMeta = metaForDeps(meta); + + for(idx = 0, len = depKeys.length; idx < len; idx++) { + depKey = depKeys[idx]; + // Lookup keys meta for depKey + keys = keysForDep(depsMeta, depKey); + // Increment the number of times depKey depends on keyName. + keys[keyName] = (keys[keyName] || 0) + 1; + // Watch the depKey + watch(obj, depKey); + } +} + +function removeDependentKeys(desc, obj, keyName, meta) { + // the descriptor has a list of dependent keys, so + // add all of its dependent keys. + var depKeys = desc._dependentKeys, depsMeta, idx, len, depKey, keys; + if (!depKeys) return; + + depsMeta = metaForDeps(meta); + + for(idx = 0, len = depKeys.length; idx < len; idx++) { + depKey = depKeys[idx]; + // Lookup keys meta for depKey + keys = keysForDep(depsMeta, depKey); + // Increment the number of times depKey depends on keyName. + keys[keyName] = (keys[keyName] || 0) - 1; + // Watch the depKey + unwatch(obj, depKey); + } +} + +// .......................................................... +// COMPUTED PROPERTY +// + +/** + A computed property transforms an objects function into a property. + + By default the function backing the computed property will only be called + once and the result will be cached. You can specify various properties + that your computed property is dependent on. This will force the cached + result to be recomputed if the dependencies are modified. + + In the following example we declare a computed property (by calling + `.property()` on the fullName function) and setup the properties + dependencies (depending on firstName and lastName). The fullName function + will be called once (regardless of how many times it is accessed) as long + as it's dependencies have not been changed. Once firstName or lastName are updated + any future calls (or anything bound) to fullName will incorporate the new + values. + + ```javascript + Person = Ember.Object.extend({ + // these will be supplied by `create` + firstName: null, + lastName: null, + + fullName: function() { + var firstName = this.get('firstName'); + var lastName = this.get('lastName'); + + return firstName + ' ' + lastName; + }.property('firstName', 'lastName') + }); + + var tom = Person.create({ + firstName: "Tom", + lastName: "Dale" + }); + + tom.get('fullName') // "Tom Dale" + ``` + + You can also define what Ember should do when setting a computed property. + If you try to set a computed property, it will be invoked with the key and + value you want to set it to. You can also accept the previous value as the + third parameter. + + ```javascript + + Person = Ember.Object.extend({ + // these will be supplied by `create` + firstName: null, + lastName: null, + + fullName: function(key, value, oldValue) { + // getter + if (arguments.length === 1) { + var firstName = this.get('firstName'); + var lastName = this.get('lastName'); + + return firstName + ' ' + lastName; + + // setter + } else { + var name = value.split(" "); + + this.set('firstName', name[0]); + this.set('lastName', name[1]); + + return value; + } + }.property('firstName', 'lastName') + }); + + var person = Person.create(); + person.set('fullName', "Peter Wagenet"); + person.get('firstName') // Peter + person.get('lastName') // Wagenet + ``` + + @class ComputedProperty + @namespace Ember + @extends Ember.Descriptor + @constructor +*/ +function ComputedProperty(func, opts) { + this.func = func; + + this._cacheable = (opts && opts.cacheable !== undefined) ? opts.cacheable : true; + this._dependentKeys = opts && opts.dependentKeys; + this._readOnly = opts && (opts.readOnly !== undefined || !!opts.readOnly); +} + +Ember.ComputedProperty = ComputedProperty; +ComputedProperty.prototype = new Ember.Descriptor(); + +var ComputedPropertyPrototype = ComputedProperty.prototype; + +/** + Properties are cacheable by default. Computed property will automatically + cache the return value of your function until one of the dependent keys changes. + + Call `volatile()` to set it into non-cached mode. When in this mode + the computed property will not automatically cache the return value. + + However, if a property is properly observable, there is no reason to disable + caching. + + @method cacheable + @param {Boolean} aFlag optional set to `false` to disable caching + @return {Ember.ComputedProperty} this + @chainable +*/ +ComputedPropertyPrototype.cacheable = function(aFlag) { + this._cacheable = aFlag !== false; + return this; +}; + +/** + Call on a computed property to set it into non-cached mode. When in this + mode the computed property will not automatically cache the return value. + + ```javascript + MyApp.outsideService = Ember.Object.create({ + value: function() { + return OutsideService.getValue(); + }.property().volatile() + }); + ``` + + @method volatile + @return {Ember.ComputedProperty} this + @chainable +*/ +ComputedPropertyPrototype.volatile = function() { + return this.cacheable(false); +}; + +/** + Call on a computed property to set it into read-only mode. When in this + mode the computed property will throw an error when set. + + ```javascript + MyApp.person = Ember.Object.create({ + guid: function() { + return 'guid-guid-guid'; + }.property().readOnly() + }); + + MyApp.person.set('guid', 'new-guid'); // will throw an exception + ``` + + @method readOnly + @return {Ember.ComputedProperty} this + @chainable +*/ +ComputedPropertyPrototype.readOnly = function(readOnly) { + this._readOnly = readOnly === undefined || !!readOnly; + return this; +}; + +/** + Sets the dependent keys on this computed property. Pass any number of + arguments containing key paths that this computed property depends on. + + ```javascript + MyApp.president = Ember.Object.create({ + fullName: Ember.computed(function() { + return this.get('firstName') + ' ' + this.get('lastName'); + + // Tell Ember that this computed property depends on firstName + // and lastName + }).property('firstName', 'lastName') + }); + ``` + + @method property + @param {String} path* zero or more property paths + @return {Ember.ComputedProperty} this + @chainable +*/ +ComputedPropertyPrototype.property = function() { + var addArg; + + + var args = []; + for (var i = 0, l = arguments.length; i < l; i++) { + + args.push(arguments[i]); + + } + this._dependentKeys = args; + return this; +}; + +/** + In some cases, you may want to annotate computed properties with additional + metadata about how they function or what values they operate on. For example, + computed property functions may close over variables that are then no longer + available for introspection. + + You can pass a hash of these values to a computed property like this: + + ``` + person: function() { + var personId = this.get('personId'); + return App.Person.create({ id: personId }); + }.property().meta({ type: App.Person }) + ``` + + The hash that you pass to the `meta()` function will be saved on the + computed property descriptor under the `_meta` key. Ember runtime + exposes a public API for retrieving these values from classes, + via the `metaForProperty()` function. + + @method meta + @param {Hash} meta + @chainable +*/ + +ComputedPropertyPrototype.meta = function(meta) { + if (arguments.length === 0) { + return this._meta || {}; + } else { + this._meta = meta; + return this; + } +}; + +/* impl descriptor API */ +ComputedPropertyPrototype.didChange = function(obj, keyName) { + // _suspended is set via a CP.set to ensure we don't clear + // the cached value set by the setter + if (this._cacheable && this._suspended !== obj) { + var meta = metaFor(obj); + if (keyName in meta.cache) { + delete meta.cache[keyName]; + removeDependentKeys(this, obj, keyName, meta); + } + } +}; + +function finishChains(chainNodes) +{ + for (var i=0, l=chainNodes.length; i 1) { + args = a_slice.call(arguments, 0, -1); + func = a_slice.call(arguments, -1)[0]; + } + + if (typeof func !== "function") { + throw new Ember.Error("Computed Property declared without a property function"); + } + + var cp = new ComputedProperty(func); + + if (args) { + cp.property.apply(cp, args); + } + + return cp; +}; + +/** + Returns the cached value for a property, if one exists. + This can be useful for peeking at the value of a computed + property that is generated lazily, without accidentally causing + it to be created. + + @method cacheFor + @for Ember + @param {Object} obj the object whose property you want to check + @param {String} key the name of the property whose cached value you want + to return + @return {Object} the cached value +*/ +Ember.cacheFor = function cacheFor(obj, key) { + var cache = metaFor(obj, false).cache; + + if (cache && key in cache) { + return cache[key]; + } +}; + +function getProperties(self, propertyNames) { + var ret = {}; + for(var i = 0; i < propertyNames.length; i++) { + ret[propertyNames[i]] = get(self, propertyNames[i]); + } + return ret; +} + +function registerComputed(name, macro) { + Ember.computed[name] = function(dependentKey) { + var args = a_slice.call(arguments); + return Ember.computed(dependentKey, function() { + return macro.apply(this, args); + }); + }; +} + +function registerComputedWithProperties(name, macro) { + Ember.computed[name] = function() { + var properties = a_slice.call(arguments); + + var computed = Ember.computed(function() { + return macro.apply(this, [getProperties(this, properties)]); + }); + + return computed.property.apply(computed, properties); + }; +} + +/** + A computed property that returns true if the value of the dependent + property is null, an empty string, empty array, or empty function. + + Note: When using `Ember.computed.empty` to watch an array make sure to + use the `array.[]` syntax so the computed can subscribe to transitions + from empty to non-empty states. + + Example + + ```javascript + var ToDoList = Ember.Object.extend({ + done: Ember.computed.empty('todos.[]') // detect array changes + }); + var todoList = ToDoList.create({todos: ['Unit Test', 'Documentation', 'Release']}); + todoList.get('done'); // false + todoList.get('todos').clear(); // [] + todoList.get('done'); // true + ``` + + @method computed.empty + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which negate + the original value for property +*/ +registerComputed('empty', function(dependentKey) { + return Ember.isEmpty(get(this, dependentKey)); +}); + +/** + A computed property that returns true if the value of the dependent + property is NOT null, an empty string, empty array, or empty function. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + hasStuff: Ember.computed.notEmpty('backpack') + }); + var hamster = Hamster.create({backpack: ['Food', 'Sleeping Bag', 'Tent']}); + hamster.get('hasStuff'); // true + hamster.get('backpack').clear(); // [] + hamster.get('hasStuff'); // false + ``` + + @method computed.notEmpty + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which returns true if + original value for property is not empty. +*/ +registerComputed('notEmpty', function(dependentKey) { + return !Ember.isEmpty(get(this, dependentKey)); +}); + +/** + A computed property that returns true if the value of the dependent + property is null or undefined. This avoids errors from JSLint complaining + about use of ==, which can be technically confusing. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + isHungry: Ember.computed.none('food') + }); + var hamster = Hamster.create(); + hamster.get('isHungry'); // true + hamster.set('food', 'Banana'); + hamster.get('isHungry'); // false + hamster.set('food', null); + hamster.get('isHungry'); // true + ``` + + @method computed.none + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which + returns true if original value for property is null or undefined. +*/ +registerComputed('none', function(dependentKey) { + return Ember.isNone(get(this, dependentKey)); +}); + +/** + A computed property that returns the inverse boolean value + of the original value for the dependent property. + + Example + + ```javascript + var User = Ember.Object.extend({ + isAnonymous: Ember.computed.not('loggedIn') + }); + var user = User.create({loggedIn: false}); + user.get('isAnonymous'); // true + user.set('loggedIn', true); + user.get('isAnonymous'); // false + ``` + + @method computed.not + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which returns + inverse of the original value for property +*/ +registerComputed('not', function(dependentKey) { + return !get(this, dependentKey); +}); + +/** + A computed property that converts the provided dependent property + into a boolean value. + + ```javascript + var Hamster = Ember.Object.extend({ + hasBananas: Ember.computed.bool('numBananas') + }); + var hamster = Hamster.create(); + hamster.get('hasBananas'); // false + hamster.set('numBananas', 0); + hamster.get('hasBananas'); // false + hamster.set('numBananas', 1); + hamster.get('hasBananas'); // true + hamster.set('numBananas', null); + hamster.get('hasBananas'); // false + ``` + + @method computed.bool + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which converts + to boolean the original value for property +*/ +registerComputed('bool', function(dependentKey) { + return !!get(this, dependentKey); +}); + +/** + A computed property which matches the original value for the + dependent property against a given RegExp, returning `true` + if they values matches the RegExp and `false` if it does not. + + Example + + ```javascript + var User = Ember.Object.extend({ + hasValidEmail: Ember.computed.match('email', /^.+@.+\..+$/) + }); + var user = User.create({loggedIn: false}); + user.get('hasValidEmail'); // false + user.set('email', ''); + user.get('hasValidEmail'); // false + user.set('email', 'ember_hamster@example.com'); + user.get('hasValidEmail'); // true + ``` + + @method computed.match + @for Ember + @param {String} dependentKey + @param {RegExp} regexp + @return {Ember.ComputedProperty} computed property which match + the original value for property against a given RegExp +*/ +registerComputed('match', function(dependentKey, regexp) { + var value = get(this, dependentKey); + return typeof value === 'string' ? regexp.test(value) : false; +}); + +/** + A computed property that returns true if the provided dependent property + is equal to the given value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + napTime: Ember.computed.equal('state', 'sleepy') + }); + var hamster = Hamster.create(); + hamster.get('napTime'); // false + hamster.set('state', 'sleepy'); + hamster.get('napTime'); // true + hamster.set('state', 'hungry'); + hamster.get('napTime'); // false + ``` + + @method computed.equal + @for Ember + @param {String} dependentKey + @param {String|Number|Object} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is equal to the given value. +*/ +registerComputed('equal', function(dependentKey, value) { + return get(this, dependentKey) === value; +}); + +/** + A computed property that returns true if the provied dependent property + is greater than the provided value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + hasTooManyBananas: Ember.computed.gt('numBananas', 10) + }); + var hamster = Hamster.create(); + hamster.get('hasTooManyBananas'); // false + hamster.set('numBananas', 3); + hamster.get('hasTooManyBananas'); // false + hamster.set('numBananas', 11); + hamster.get('hasTooManyBananas'); // true + ``` + + @method computed.gt + @for Ember + @param {String} dependentKey + @param {Number} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is greater then given value. +*/ +registerComputed('gt', function(dependentKey, value) { + return get(this, dependentKey) > value; +}); + +/** + A computed property that returns true if the provided dependent property + is greater than or equal to the provided value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + hasTooManyBananas: Ember.computed.gte('numBananas', 10) + }); + var hamster = Hamster.create(); + hamster.get('hasTooManyBananas'); // false + hamster.set('numBananas', 3); + hamster.get('hasTooManyBananas'); // false + hamster.set('numBananas', 10); + hamster.get('hasTooManyBananas'); // true + ``` + + @method computed.gte + @for Ember + @param {String} dependentKey + @param {Number} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is greater or equal then given value. +*/ +registerComputed('gte', function(dependentKey, value) { + return get(this, dependentKey) >= value; +}); + +/** + A computed property that returns true if the provided dependent property + is less than the provided value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + needsMoreBananas: Ember.computed.lt('numBananas', 3) + }); + var hamster = Hamster.create(); + hamster.get('needsMoreBananas'); // true + hamster.set('numBananas', 3); + hamster.get('needsMoreBananas'); // false + hamster.set('numBananas', 2); + hamster.get('needsMoreBananas'); // true + ``` + + @method computed.lt + @for Ember + @param {String} dependentKey + @param {Number} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is less then given value. +*/ +registerComputed('lt', function(dependentKey, value) { + return get(this, dependentKey) < value; +}); + +/** + A computed property that returns true if the provided dependent property + is less than or equal to the provided value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + needsMoreBananas: Ember.computed.lte('numBananas', 3) + }); + var hamster = Hamster.create(); + hamster.get('needsMoreBananas'); // true + hamster.set('numBananas', 5); + hamster.get('needsMoreBananas'); // false + hamster.set('numBananas', 3); + hamster.get('needsMoreBananas'); // true + ``` + + @method computed.lte + @for Ember + @param {String} dependentKey + @param {Number} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is less or equal then given value. +*/ +registerComputed('lte', function(dependentKey, value) { + return get(this, dependentKey) <= value; +}); + +/** + A computed property that performs a logical `and` on the + original values for the provided dependent properties. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + readyForCamp: Ember.computed.and('hasTent', 'hasBackpack') + }); + var hamster = Hamster.create(); + hamster.get('readyForCamp'); // false + hamster.set('hasTent', true); + hamster.get('readyForCamp'); // false + hamster.set('hasBackpack', true); + hamster.get('readyForCamp'); // true + ``` + + @method computed.and + @for Ember + @param {String} dependentKey* + @return {Ember.ComputedProperty} computed property which performs + a logical `and` on the values of all the original values for properties. +*/ +registerComputedWithProperties('and', function(properties) { + for (var key in properties) { + if (properties.hasOwnProperty(key) && !properties[key]) { + return false; + } + } + return true; +}); + +/** + A computed property which performs a logical `or` on the + original values for the provided dependent properties. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + readyForRain: Ember.computed.or('hasJacket', 'hasUmbrella') + }); + var hamster = Hamster.create(); + hamster.get('readyForRain'); // false + hamster.set('hasJacket', true); + hamster.get('readyForRain'); // true + ``` + + @method computed.or + @for Ember + @param {String} dependentKey* + @return {Ember.ComputedProperty} computed property which performs + a logical `or` on the values of all the original values for properties. +*/ +registerComputedWithProperties('or', function(properties) { + for (var key in properties) { + if (properties.hasOwnProperty(key) && properties[key]) { + return true; + } + } + return false; +}); + +/** + A computed property that returns the first truthy value + from a list of dependent properties. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + hasClothes: Ember.computed.any('hat', 'shirt') + }); + var hamster = Hamster.create(); + hamster.get('hasClothes'); // null + hamster.set('shirt', 'Hawaiian Shirt'); + hamster.get('hasClothes'); // 'Hawaiian Shirt' + ``` + + @method computed.any + @for Ember + @param {String} dependentKey* + @return {Ember.ComputedProperty} computed property which returns + the first truthy value of given list of properties. +*/ +registerComputedWithProperties('any', function(properties) { + for (var key in properties) { + if (properties.hasOwnProperty(key) && properties[key]) { + return properties[key]; + } + } + return null; +}); + +/** + A computed property that returns the array of values + for the provided dependent properties. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + clothes: Ember.computed.map('hat', 'shirt') + }); + var hamster = Hamster.create(); + hamster.get('clothes'); // [null, null] + hamster.set('hat', 'Camp Hat'); + hamster.set('shirt', 'Camp Shirt'); + hamster.get('clothes'); // ['Camp Hat', 'Camp Shirt'] + ``` + + @method computed.map + @for Ember + @param {String} dependentKey* + @return {Ember.ComputedProperty} computed property which maps + values of all passed properties in to an array. +*/ +registerComputedWithProperties('collect', function(properties) { + var res = []; + for (var key in properties) { + if (properties.hasOwnProperty(key)) { + if (Ember.isNone(properties[key])) { + res.push(null); + } else { + res.push(properties[key]); + } + } + } + return res; +}); + +/** + Creates a new property that is an alias for another property + on an object. Calls to `get` or `set` this property behave as + though they were called on the original property. + + ```javascript + Person = Ember.Object.extend({ + name: 'Alex Matchneer', + nomen: Ember.computed.alias('name') + }); + + alex = Person.create(); + alex.get('nomen'); // 'Alex Matchneer' + alex.get('name'); // 'Alex Matchneer' + + alex.set('nomen', '@machty'); + alex.get('name'); // '@machty' + ``` + @method computed.alias + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which creates an + alias to the original value for property. +*/ +Ember.computed.alias = function(dependentKey) { + return Ember.computed(dependentKey, function(key, value) { + if (arguments.length > 1) { + set(this, dependentKey, value); + return value; + } else { + return get(this, dependentKey); + } + }); +}; + +/** + Where `computed.alias` aliases `get` and `set`, and allows for bidirectional + data flow, `computed.oneWay` only provides an aliased `get`. The `set` will + not mutate the upstream property, rather causes the current property to + become the value set. This causes the downstream property to permentantly + diverge from the upstream property. + + Example + + ```javascript + User = Ember.Object.extend({ + firstName: null, + lastName: null, + nickName: Ember.computed.oneWay('firstName') + }); + + user = User.create({ + firstName: 'Teddy', + lastName: 'Zeenny' + }); + + user.get('nickName'); + # 'Teddy' + + user.set('nickName', 'TeddyBear'); + # 'TeddyBear' + + user.get('firstName'); + # 'Teddy' + ``` + + @method computed.oneWay + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which creates a + one way computed property to the original value for property. +*/ +Ember.computed.oneWay = function(dependentKey) { + return Ember.computed(dependentKey, function() { + return get(this, dependentKey); + }); +}; + + +/** + A computed property that acts like a standard getter and setter, + but returns the value at the provided `defaultPath` if the + property itself has not been set to a value + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + wishList: Ember.computed.defaultTo('favoriteFood') + }); + var hamster = Hamster.create({favoriteFood: 'Banana'}); + hamster.get('wishList'); // 'Banana' + hamster.set('wishList', 'More Unit Tests'); + hamster.get('wishList'); // 'More Unit Tests' + hamster.get('favoriteFood'); // 'Banana' + ``` + + @method computed.defaultTo + @for Ember + @param {String} defaultPath + @return {Ember.ComputedProperty} computed property which acts like + a standard getter and setter, but defaults to the value from `defaultPath`. +*/ +Ember.computed.defaultTo = function(defaultPath) { + return Ember.computed(function(key, newValue, cachedValue) { + if (arguments.length === 1) { + return cachedValue != null ? cachedValue : get(this, defaultPath); + } + return newValue != null ? newValue : get(this, defaultPath); + }); +}; + + +})(); + + + +(function() { +// Ember.tryFinally +/** +@module ember-metal +*/ + +var AFTER_OBSERVERS = ':change', + BEFORE_OBSERVERS = ':before'; + + +function changeEvent(keyName) { + return keyName+AFTER_OBSERVERS; +} + +function beforeEvent(keyName) { + return keyName+BEFORE_OBSERVERS; +} + +/** + @method addObserver + @param obj + @param {String} path + @param {Object|Function} targetOrMethod + @param {Function|String} [method] +*/ +Ember.addObserver = function(obj, _path, target, method) { + + Ember.addListener(obj, changeEvent(_path), target, method); + Ember.watch(obj, _path); + + + return this; +}; + +Ember.observersFor = function(obj, path) { + return Ember.listenersFor(obj, changeEvent(path)); +}; + +/** + @method removeObserver + @param obj + @param {String} path + @param {Object|Function} targetOrMethod + @param {Function|String} [method] +*/ +Ember.removeObserver = function(obj, _path, target, method) { + + Ember.unwatch(obj, _path); + Ember.removeListener(obj, changeEvent(_path), target, method); + + return this; +}; + +/** + @method addBeforeObserver + @param obj + @param {String} path + @param {Object|Function} targetOrMethod + @param {Function|String} [method] +*/ +Ember.addBeforeObserver = function(obj, _path, target, method) { + + Ember.addListener(obj, beforeEvent(_path), target, method); + Ember.watch(obj, _path); + + return this; +}; + +// Suspend observer during callback. +// +// This should only be used by the target of the observer +// while it is setting the observed path. +Ember._suspendBeforeObserver = function(obj, path, target, method, callback) { + return Ember._suspendListener(obj, beforeEvent(path), target, method, callback); +}; + +Ember._suspendObserver = function(obj, path, target, method, callback) { + return Ember._suspendListener(obj, changeEvent(path), target, method, callback); +}; + +var map = Ember.ArrayPolyfills.map; + +Ember._suspendBeforeObservers = function(obj, paths, target, method, callback) { + var events = map.call(paths, beforeEvent); + return Ember._suspendListeners(obj, events, target, method, callback); +}; + +Ember._suspendObservers = function(obj, paths, target, method, callback) { + var events = map.call(paths, changeEvent); + return Ember._suspendListeners(obj, events, target, method, callback); +}; + +Ember.beforeObserversFor = function(obj, path) { + return Ember.listenersFor(obj, beforeEvent(path)); +}; + +/** + @method removeBeforeObserver + @param obj + @param {String} path + @param {Object|Function} targetOrMethod + @param {Function|String} [method] +*/ +Ember.removeBeforeObserver = function(obj, _path, target, method) { + + Ember.unwatch(obj, _path); + Ember.removeListener(obj, beforeEvent(_path), target, method); + + return this; +}; + +})(); + + + +(function() { +define("backburner/queue", + ["exports"], + function(__exports__) { + "use strict"; + function Queue(daq, name, options) { + this.daq = daq; + this.name = name; + this.options = options; + this._queue = []; + } + + Queue.prototype = { + daq: null, + name: null, + options: null, + _queue: null, + + push: function(target, method, args, stack) { + var queue = this._queue; + queue.push(target, method, args, stack); + return {queue: this, target: target, method: method}; + }, + + pushUnique: function(target, method, args, stack) { + var queue = this._queue, currentTarget, currentMethod, i, l; + + for (i = 0, l = queue.length; i < l; i += 4) { + currentTarget = queue[i]; + currentMethod = queue[i+1]; + + if (currentTarget === target && currentMethod === method) { + queue[i+2] = args; // replace args + queue[i+3] = stack; // replace stack + return {queue: this, target: target, method: method}; // TODO: test this code path + } + } + + this._queue.push(target, method, args, stack); + return {queue: this, target: target, method: method}; + }, + + // TODO: remove me, only being used for Ember.run.sync + flush: function() { + var queue = this._queue, + options = this.options, + before = options && options.before, + after = options && options.after, + target, method, args, stack, i, l = queue.length; + + if (l && before) { before(); } + for (i = 0; i < l; i += 4) { + target = queue[i]; + method = queue[i+1]; + args = queue[i+2]; + stack = queue[i+3]; // Debugging assistance + + // TODO: error handling + if (args && args.length > 0) { + method.apply(target, args); + } else { + method.call(target); + } + } + if (l && after) { after(); } + + // check if new items have been added + if (queue.length > l) { + this._queue = queue.slice(l); + this.flush(); + } else { + this._queue.length = 0; + } + }, + + cancel: function(actionToCancel) { + var queue = this._queue, currentTarget, currentMethod, i, l; + + for (i = 0, l = queue.length; i < l; i += 4) { + currentTarget = queue[i]; + currentMethod = queue[i+1]; + + if (currentTarget === actionToCancel.target && currentMethod === actionToCancel.method) { + queue.splice(i, 4); + return true; + } + } + + // if not found in current queue + // could be in the queue that is being flushed + queue = this._queueBeingFlushed; + if (!queue) { + return; + } + for (i = 0, l = queue.length; i < l; i += 4) { + currentTarget = queue[i]; + currentMethod = queue[i+1]; + + if (currentTarget === actionToCancel.target && currentMethod === actionToCancel.method) { + // don't mess with array during flush + // just nullify the method + queue[i+1] = null; + return true; + } + } + } + }; + + + __exports__.Queue = Queue; + }); + +define("backburner/deferred_action_queues", + ["backburner/queue","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Queue = __dependency1__.Queue; + + function DeferredActionQueues(queueNames, options) { + var queues = this.queues = {}; + this.queueNames = queueNames = queueNames || []; + + var queueName; + for (var i = 0, l = queueNames.length; i < l; i++) { + queueName = queueNames[i]; + queues[queueName] = new Queue(this, queueName, options[queueName]); + } + } + + DeferredActionQueues.prototype = { + queueNames: null, + queues: null, + + schedule: function(queueName, target, method, args, onceFlag, stack) { + var queues = this.queues, + queue = queues[queueName]; + + if (!queue) { throw new Error("You attempted to schedule an action in a queue (" + queueName + ") that doesn't exist"); } + + if (onceFlag) { + return queue.pushUnique(target, method, args, stack); + } else { + return queue.push(target, method, args, stack); + } + }, + + flush: function() { + var queues = this.queues, + queueNames = this.queueNames, + queueName, queue, queueItems, priorQueueNameIndex, + queueNameIndex = 0, numberOfQueues = queueNames.length; + + outerloop: + while (queueNameIndex < numberOfQueues) { + queueName = queueNames[queueNameIndex]; + queue = queues[queueName]; + queueItems = queue._queueBeingFlushed = queue._queue.slice(); + queue._queue = []; + + var options = queue.options, + before = options && options.before, + after = options && options.after, + target, method, args, stack, + queueIndex = 0, numberOfQueueItems = queueItems.length; + + if (numberOfQueueItems && before) { before(); } + while (queueIndex < numberOfQueueItems) { + target = queueItems[queueIndex]; + method = queueItems[queueIndex+1]; + args = queueItems[queueIndex+2]; + stack = queueItems[queueIndex+3]; // Debugging assistance + + if (typeof method === 'string') { method = target[method]; } + + // method could have been nullified / canceled during flush + if (method) { + // TODO: error handling + if (args && args.length > 0) { + method.apply(target, args); + } else { + method.call(target); + } + } + + queueIndex += 4; + } + queue._queueBeingFlushed = null; + if (numberOfQueueItems && after) { after(); } + + if ((priorQueueNameIndex = indexOfPriorQueueWithActions(this, queueNameIndex)) !== -1) { + queueNameIndex = priorQueueNameIndex; + continue outerloop; + } + + queueNameIndex++; + } + } + }; + + function indexOfPriorQueueWithActions(daq, currentQueueIndex) { + var queueName, queue; + + for (var i = 0, l = currentQueueIndex; i <= l; i++) { + queueName = daq.queueNames[i]; + queue = daq.queues[queueName]; + if (queue._queue.length) { return i; } + } + + return -1; + } + + + __exports__.DeferredActionQueues = DeferredActionQueues; + }); + +define("backburner", + ["backburner/deferred_action_queues","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var DeferredActionQueues = __dependency1__.DeferredActionQueues; + + var slice = [].slice, + pop = [].pop, + throttlers = [], + debouncees = [], + timers = [], + autorun, laterTimer, laterTimerExpiresAt, + global = this, + NUMBER = /\d+/; + + function isCoercableNumber(number) { + return typeof number === 'number' || NUMBER.test(number); + } + + function Backburner(queueNames, options) { + this.queueNames = queueNames; + this.options = options || {}; + if (!this.options.defaultQueue) { + this.options.defaultQueue = queueNames[0]; + } + this.instanceStack = []; + } + + Backburner.prototype = { + queueNames: null, + options: null, + currentInstance: null, + instanceStack: null, + + begin: function() { + var onBegin = this.options && this.options.onBegin, + previousInstance = this.currentInstance; + + if (previousInstance) { + this.instanceStack.push(previousInstance); + } + + this.currentInstance = new DeferredActionQueues(this.queueNames, this.options); + if (onBegin) { + onBegin(this.currentInstance, previousInstance); + } + }, + + end: function() { + var onEnd = this.options && this.options.onEnd, + currentInstance = this.currentInstance, + nextInstance = null; + + try { + currentInstance.flush(); + } finally { + this.currentInstance = null; + + if (this.instanceStack.length) { + nextInstance = this.instanceStack.pop(); + this.currentInstance = nextInstance; + } + + if (onEnd) { + onEnd(currentInstance, nextInstance); + } + } + }, + + run: function(target, method /*, args */) { + var ret; + this.begin(); + + if (!method) { + method = target; + target = null; + } + + if (typeof method === 'string') { + method = target[method]; + } + + // Prevent Safari double-finally. + var finallyAlreadyCalled = false; + try { + if (arguments.length > 2) { + ret = method.apply(target, slice.call(arguments, 2)); + } else { + ret = method.call(target); + } + } finally { + if (!finallyAlreadyCalled) { + finallyAlreadyCalled = true; + this.end(); + } + } + return ret; + }, + + defer: function(queueName, target, method /* , args */) { + if (!method) { + method = target; + target = null; + } + + if (typeof method === 'string') { + method = target[method]; + } + + var stack = this.DEBUG ? new Error().stack : undefined, + args = arguments.length > 3 ? slice.call(arguments, 3) : undefined; + if (!this.currentInstance) { createAutorun(this); } + return this.currentInstance.schedule(queueName, target, method, args, false, stack); + }, + + deferOnce: function(queueName, target, method /* , args */) { + if (!method) { + method = target; + target = null; + } + + if (typeof method === 'string') { + method = target[method]; + } + + var stack = this.DEBUG ? new Error().stack : undefined, + args = arguments.length > 3 ? slice.call(arguments, 3) : undefined; + if (!this.currentInstance) { createAutorun(this); } + return this.currentInstance.schedule(queueName, target, method, args, true, stack); + }, + + setTimeout: function() { + var args = slice.call(arguments); + var length = args.length; + var method, wait, target; + var self = this; + var methodOrTarget, methodOrWait, methodOrArgs; + + if (length === 0) { + return; + } else if (length === 1) { + method = args.shift(); + wait = 0; + } else if (length === 2) { + methodOrTarget = args[0]; + methodOrWait = args[1]; + + if (typeof methodOrWait === 'function' || typeof methodOrTarget[methodOrWait] === 'function') { + target = args.shift(); + method = args.shift(); + wait = 0; + } else if (isCoercableNumber(methodOrWait)) { + method = args.shift(); + wait = args.shift(); + } else { + method = args.shift(); + wait = 0; + } + } else { + var last = args[args.length - 1]; + + if (isCoercableNumber(last)) { + wait = args.pop(); + } + + methodOrTarget = args[0]; + methodOrArgs = args[1]; + + if (typeof methodOrArgs === 'function' || (typeof methodOrArgs === 'string' && + methodOrTarget !== null && + methodOrArgs in methodOrTarget)) { + target = args.shift(); + method = args.shift(); + } else { + method = args.shift(); + } + } + + var executeAt = (+new Date()) + parseInt(wait, 10); + + if (typeof method === 'string') { + method = target[method]; + } + + function fn() { + method.apply(target, args); + } + + // find position to insert - TODO: binary search + var i, l; + for (i = 0, l = timers.length; i < l; i += 2) { + if (executeAt < timers[i]) { break; } + } + + timers.splice(i, 0, executeAt, fn); + + if (laterTimer && laterTimerExpiresAt < executeAt) { return fn; } + + if (laterTimer) { + clearTimeout(laterTimer); + laterTimer = null; + } + laterTimer = global.setTimeout(function() { + executeTimers(self); + laterTimer = null; + laterTimerExpiresAt = null; + }, wait); + laterTimerExpiresAt = executeAt; + + return fn; + }, + + throttle: function(target, method /* , args, wait */) { + var self = this, + args = arguments, + wait = parseInt(pop.call(args), 10), + throttler; + + for (var i = 0, l = throttlers.length; i < l; i++) { + throttler = throttlers[i]; + if (throttler[0] === target && throttler[1] === method) { return; } // do nothing + } + + var timer = global.setTimeout(function() { + self.run.apply(self, args); + + // remove throttler + var index = -1; + for (var i = 0, l = throttlers.length; i < l; i++) { + throttler = throttlers[i]; + if (throttler[0] === target && throttler[1] === method) { + index = i; + break; + } + } + + if (index > -1) { throttlers.splice(index, 1); } + }, wait); + + throttlers.push([target, method, timer]); + }, + + debounce: function(target, method /* , args, wait, [immediate] */) { + var self = this, + args = arguments, + immediate = pop.call(args), + wait, + index, + debouncee; + + if (typeof immediate === "number" || typeof immediate === "string") { + wait = immediate; + immediate = false; + } else { + wait = pop.call(args); + } + + wait = parseInt(wait, 10); + // Remove debouncee + index = findDebouncee(target, method); + + if (index !== -1) { + debouncee = debouncees[index]; + debouncees.splice(index, 1); + clearTimeout(debouncee[2]); + } + + var timer = global.setTimeout(function() { + if (!immediate) { + self.run.apply(self, args); + } + index = findDebouncee(target, method); + if (index) { + debouncees.splice(index, 1); + } + }, wait); + + if (immediate && index === -1) { + self.run.apply(self, args); + } + + debouncees.push([target, method, timer]); + }, + + cancelTimers: function() { + var i, len; + + for (i = 0, len = throttlers.length; i < len; i++) { + clearTimeout(throttlers[i][2]); + } + throttlers = []; + + for (i = 0, len = debouncees.length; i < len; i++) { + clearTimeout(debouncees[i][2]); + } + debouncees = []; + + if (laterTimer) { + clearTimeout(laterTimer); + laterTimer = null; + } + timers = []; + + if (autorun) { + clearTimeout(autorun); + autorun = null; + } + }, + + hasTimers: function() { + return !!timers.length || autorun; + }, + + cancel: function(timer) { + if (timer && typeof timer === 'object' && timer.queue && timer.method) { // we're cancelling a deferOnce + return timer.queue.cancel(timer); + } else if (typeof timer === 'function') { // we're cancelling a setTimeout + for (var i = 0, l = timers.length; i < l; i += 2) { + if (timers[i + 1] === timer) { + timers.splice(i, 2); // remove the two elements + return true; + } + } + } else { + return; // timer was null or not a timer + } + } + }; + + Backburner.prototype.schedule = Backburner.prototype.defer; + Backburner.prototype.scheduleOnce = Backburner.prototype.deferOnce; + Backburner.prototype.later = Backburner.prototype.setTimeout; + + function createAutorun(backburner) { + backburner.begin(); + autorun = global.setTimeout(function() { + autorun = null; + backburner.end(); + }); + } + + function executeTimers(self) { + var now = +new Date(), + time, fns, i, l; + + self.run(function() { + // TODO: binary search + for (i = 0, l = timers.length; i < l; i += 2) { + time = timers[i]; + if (time > now) { break; } + } + + fns = timers.splice(0, i); + + for (i = 1, l = fns.length; i < l; i += 2) { + self.schedule(self.options.defaultQueue, null, fns[i]); + } + }); + + if (timers.length) { + laterTimer = global.setTimeout(function() { + executeTimers(self); + laterTimer = null; + laterTimerExpiresAt = null; + }, timers[0] - now); + laterTimerExpiresAt = timers[0]; + } + } + + function findDebouncee(target, method) { + var debouncee, + index = -1; + + for (var i = 0, l = debouncees.length; i < l; i++) { + debouncee = debouncees[i]; + if (debouncee[0] === target && debouncee[1] === method) { + index = i; + break; + } + } + + return index; + } + + + __exports__.Backburner = Backburner; + }); + +})(); + + + +(function() { +var onBegin = function(current) { + Ember.run.currentRunLoop = current; +}; + +var onEnd = function(current, next) { + Ember.run.currentRunLoop = next; +}; + +var Backburner = requireModule('backburner').Backburner, + backburner = new Backburner(['sync', 'actions', 'destroy'], { + sync: { + before: Ember.beginPropertyChanges, + after: Ember.endPropertyChanges + }, + defaultQueue: 'actions', + onBegin: onBegin, + onEnd: onEnd + }), + slice = [].slice; + +// .......................................................... +// Ember.run - this is ideally the only public API the dev sees +// + +/** + Runs the passed target and method inside of a RunLoop, ensuring any + deferred actions including bindings and views updates are flushed at the + end. + + Normally you should not need to invoke this method yourself. However if + you are implementing raw event handlers when interfacing with other + libraries or plugins, you should probably wrap all of your code inside this + call. + + ```javascript + Ember.run(function() { + // code to be execute within a RunLoop + }); + ``` + + @class run + @namespace Ember + @static + @constructor + @param {Object} [target] target of method to call + @param {Function|String} method Method to invoke. + May be a function or a string. If you pass a string + then it will be looked up on the passed target. + @param {Object} [args*] Any additional arguments you wish to pass to the method. + @return {Object} return value from invoking the passed function. +*/ +Ember.run = function(target, method) { + var ret; + + if (Ember.onerror) { + try { + ret = backburner.run.apply(backburner, arguments); + } catch (e) { + Ember.onerror(e); + } + } else { + ret = backburner.run.apply(backburner, arguments); + } + + return ret; +}; + +/** + + If no run-loop is present, it creates a new one. If a run loop is + present it will queue itself to run on the existing run-loops action + queue. + + Please note: This is not for normal usage, and should be used sparingly. + + If invoked when not within a run loop: + + ```javascript + Ember.run.join(function() { + // creates a new run-loop + }); + ``` + + Alternatively, if called within an existing run loop: + + ```javascript + Ember.run(function() { + // creates a new run-loop + Ember.run.join(function() { + // joins with the existing run-loop, and queues for invocation on + // the existing run-loops action queue. + }); + }); + ``` + + @method join + @namespace Ember + @param {Object} [target] target of method to call + @param {Function|String} method Method to invoke. + May be a function or a string. If you pass a string + then it will be looked up on the passed target. + @param {Object} [args*] Any additional arguments you wish to pass to the method. + @return {Object} return value from invoking the passed function. Please note, + when called within an existing loop, no return value is possible. +*/ +Ember.run.join = function(target, method) { + if (!Ember.run.currentRunLoop) { + return Ember.run.apply(Ember.run, arguments); + } + + var args = slice.call(arguments); + args.unshift('actions'); + Ember.run.schedule.apply(Ember.run, args); +}; + +Ember.run.backburner = backburner; + +var run = Ember.run; + +Ember.run.currentRunLoop = null; + +Ember.run.queues = backburner.queueNames; + +/** + Begins a new RunLoop. Any deferred actions invoked after the begin will + be buffered until you invoke a matching call to `Ember.run.end()`. This is + a lower-level way to use a RunLoop instead of using `Ember.run()`. + + ```javascript + Ember.run.begin(); + // code to be execute within a RunLoop + Ember.run.end(); + ``` + + @method begin + @return {void} +*/ +Ember.run.begin = function() { + backburner.begin(); +}; + +/** + Ends a RunLoop. This must be called sometime after you call + `Ember.run.begin()` to flush any deferred actions. This is a lower-level way + to use a RunLoop instead of using `Ember.run()`. + + ```javascript + Ember.run.begin(); + // code to be execute within a RunLoop + Ember.run.end(); + ``` + + @method end + @return {void} +*/ +Ember.run.end = function() { + backburner.end(); +}; + +/** + Array of named queues. This array determines the order in which queues + are flushed at the end of the RunLoop. You can define your own queues by + simply adding the queue name to this array. Normally you should not need + to inspect or modify this property. + + @property queues + @type Array + @default ['sync', 'actions', 'destroy'] +*/ + +/** + Adds the passed target/method and any optional arguments to the named + queue to be executed at the end of the RunLoop. If you have not already + started a RunLoop when calling this method one will be started for you + automatically. + + At the end of a RunLoop, any methods scheduled in this way will be invoked. + Methods will be invoked in an order matching the named queues defined in + the `Ember.run.queues` property. + + ```javascript + Ember.run.schedule('sync', this, function() { + // this will be executed in the first RunLoop queue, when bindings are synced + console.log("scheduled on sync queue"); + }); + + Ember.run.schedule('actions', this, function() { + // this will be executed in the 'actions' queue, after bindings have synced. + console.log("scheduled on actions queue"); + }); + + // Note the functions will be run in order based on the run queues order. Output would be: + // scheduled on sync queue + // scheduled on actions queue + ``` + + @method schedule + @param {String} queue The name of the queue to schedule against. + Default queues are 'sync' and 'actions' + @param {Object} [target] target object to use as the context when invoking a method. + @param {String|Function} method The method to invoke. If you pass a string it + will be resolved on the target object at the time the scheduled item is + invoked allowing you to change the target function. + @param {Object} [arguments*] Optional arguments to be passed to the queued method. + @return {void} +*/ +Ember.run.schedule = function(queue, target, method) { + checkAutoRun(); + backburner.schedule.apply(backburner, arguments); +}; + +// Used by global test teardown +Ember.run.hasScheduledTimers = function() { + return backburner.hasTimers(); +}; + +// Used by global test teardown +Ember.run.cancelTimers = function () { + backburner.cancelTimers(); +}; + +/** + Immediately flushes any events scheduled in the 'sync' queue. Bindings + use this queue so this method is a useful way to immediately force all + bindings in the application to sync. + + You should call this method anytime you need any changed state to propagate + throughout the app immediately without repainting the UI (which happens + in the later 'render' queue added by the `ember-views` package). + + ```javascript + Ember.run.sync(); + ``` + + @method sync + @return {void} +*/ +Ember.run.sync = function() { + if (backburner.currentInstance) { + backburner.currentInstance.queues.sync.flush(); + } +}; + +/** + Invokes the passed target/method and optional arguments after a specified + period if time. The last parameter of this method must always be a number + of milliseconds. + + You should use this method whenever you need to run some action after a + period of time instead of using `setTimeout()`. This method will ensure that + items that expire during the same script execution cycle all execute + together, which is often more efficient than using a real setTimeout. + + ```javascript + Ember.run.later(myContext, function() { + // code here will execute within a RunLoop in about 500ms with this == myContext + }, 500); + ``` + + @method later + @param {Object} [target] target of method to invoke + @param {Function|String} method The method to invoke. + If you pass a string it will be resolved on the + target at the time the method is invoked. + @param {Object} [args*] Optional arguments to pass to the timeout. + @param {Number} wait Number of milliseconds to wait. + @return {String} a string you can use to cancel the timer in + `Ember.run.cancel` later. +*/ +Ember.run.later = function(target, method) { + return backburner.later.apply(backburner, arguments); +}; + +/** + Schedule a function to run one time during the current RunLoop. This is equivalent + to calling `scheduleOnce` with the "actions" queue. + + @method once + @param {Object} [target] The target of the method to invoke. + @param {Function|String} method The method to invoke. + If you pass a string it will be resolved on the + target at the time the method is invoked. + @param {Object} [args*] Optional arguments to pass to the timeout. + @return {Object} timer +*/ +Ember.run.once = function(target, method) { + checkAutoRun(); + var args = slice.call(arguments); + args.unshift('actions'); + return backburner.scheduleOnce.apply(backburner, args); +}; + +/** + Schedules a function to run one time in a given queue of the current RunLoop. + Calling this method with the same queue/target/method combination will have + no effect (past the initial call). + + Note that although you can pass optional arguments these will not be + considered when looking for duplicates. New arguments will replace previous + calls. + + ```javascript + Ember.run(function() { + var sayHi = function() { console.log('hi'); } + Ember.run.scheduleOnce('afterRender', myContext, sayHi); + Ember.run.scheduleOnce('afterRender', myContext, sayHi); + // sayHi will only be executed once, in the afterRender queue of the RunLoop + }); + ``` + + Also note that passing an anonymous function to `Ember.run.scheduleOnce` will + not prevent additional calls with an identical anonymous function from + scheduling the items multiple times, e.g.: + + ```javascript + function scheduleIt() { + Ember.run.scheduleOnce('actions', myContext, function() { console.log("Closure"); }); + } + scheduleIt(); + scheduleIt(); + // "Closure" will print twice, even though we're using `Ember.run.scheduleOnce`, + // because the function we pass to it is anonymous and won't match the + // previously scheduled operation. + ``` + + Available queues, and their order, can be found at `Ember.run.queues` + + @method scheduleOnce + @param {String} [queue] The name of the queue to schedule against. Default queues are 'sync' and 'actions'. + @param {Object} [target] The target of the method to invoke. + @param {Function|String} method The method to invoke. + If you pass a string it will be resolved on the + target at the time the method is invoked. + @param {Object} [args*] Optional arguments to pass to the timeout. + @return {Object} timer +*/ +Ember.run.scheduleOnce = function(queue, target, method) { + checkAutoRun(); + return backburner.scheduleOnce.apply(backburner, arguments); +}; + +/** + Schedules an item to run from within a separate run loop, after + control has been returned to the system. This is equivalent to calling + `Ember.run.later` with a wait time of 1ms. + + ```javascript + Ember.run.next(myContext, function() { + // code to be executed in the next run loop, which will be scheduled after the current one + }); + ``` + + Multiple operations scheduled with `Ember.run.next` will coalesce + into the same later run loop, along with any other operations + scheduled by `Ember.run.later` that expire right around the same + time that `Ember.run.next` operations will fire. + + Note that there are often alternatives to using `Ember.run.next`. + For instance, if you'd like to schedule an operation to happen + after all DOM element operations have completed within the current + run loop, you can make use of the `afterRender` run loop queue (added + by the `ember-views` package, along with the preceding `render` queue + where all the DOM element operations happen). Example: + + ```javascript + App.MyCollectionView = Ember.CollectionView.extend({ + didInsertElement: function() { + Ember.run.scheduleOnce('afterRender', this, 'processChildElements'); + }, + processChildElements: function() { + // ... do something with collectionView's child view + // elements after they've finished rendering, which + // can't be done within the CollectionView's + // `didInsertElement` hook because that gets run + // before the child elements have been added to the DOM. + } + }); + ``` + + One benefit of the above approach compared to using `Ember.run.next` is + that you will be able to perform DOM/CSS operations before unprocessed + elements are rendered to the screen, which may prevent flickering or + other artifacts caused by delaying processing until after rendering. + + The other major benefit to the above approach is that `Ember.run.next` + introduces an element of non-determinism, which can make things much + harder to test, due to its reliance on `setTimeout`; it's much harder + to guarantee the order of scheduled operations when they are scheduled + outside of the current run loop, i.e. with `Ember.run.next`. + + @method next + @param {Object} [target] target of method to invoke + @param {Function|String} method The method to invoke. + If you pass a string it will be resolved on the + target at the time the method is invoked. + @param {Object} [args*] Optional arguments to pass to the timeout. + @return {Object} timer +*/ +Ember.run.next = function() { + var args = slice.call(arguments); + args.push(1); + return backburner.later.apply(backburner, args); +}; + +/** + Cancels a scheduled item. Must be a value returned by `Ember.run.later()`, + `Ember.run.once()`, or `Ember.run.next()`. + + ```javascript + var runNext = Ember.run.next(myContext, function() { + // will not be executed + }); + Ember.run.cancel(runNext); + + var runLater = Ember.run.later(myContext, function() { + // will not be executed + }, 500); + Ember.run.cancel(runLater); + + var runOnce = Ember.run.once(myContext, function() { + // will not be executed + }); + Ember.run.cancel(runOnce); + ``` + + @method cancel + @param {Object} timer Timer object to cancel + @return {void} +*/ +Ember.run.cancel = function(timer) { + return backburner.cancel(timer); +}; + +/** + Delay calling the target method until the debounce period has elapsed + with no additional debounce calls. If `debounce` is called again before + the specified time has elapsed, the timer is reset and the entire period + must pass again before the target method is called. + + This method should be used when an event may be called multiple times + but the action should only be called once when the event is done firing. + A common example is for scroll events where you only want updates to + happen once scrolling has ceased. + + ```javascript + var myFunc = function() { console.log(this.name + ' ran.'); }; + var myContext = {name: 'debounce'}; + + Ember.run.debounce(myContext, myFunc, 150); + + // less than 150ms passes + + Ember.run.debounce(myContext, myFunc, 150); + + // 150ms passes + // myFunc is invoked with context myContext + // console logs 'debounce ran.' one time. + ``` + + @method debounce + @param {Object} [target] target of method to invoke + @param {Function|String} method The method to invoke. + May be a function or a string. If you pass a string + then it will be looked up on the passed target. + @param {Object} [args*] Optional arguments to pass to the timeout. + @param {Number} wait Number of milliseconds to wait. + @param {Boolean} immediate Trigger the function on the leading instead of the trailing edge of the wait interval. + @return {void} +*/ +Ember.run.debounce = function() { + return backburner.debounce.apply(backburner, arguments); +}; + +/** + Ensure that the target method is never called more frequently than + the specified spacing period. + + ```javascript + var myFunc = function() { console.log(this.name + ' ran.'); }; + var myContext = {name: 'throttle'}; + + Ember.run.throttle(myContext, myFunc, 150); + + // 50ms passes + Ember.run.throttle(myContext, myFunc, 150); + + // 50ms passes + Ember.run.throttle(myContext, myFunc, 150); + + // 50ms passes + Ember.run.throttle(myContext, myFunc, 150); + + // 150ms passes + // myFunc is invoked with context myContext + // console logs 'throttle ran.' twice, 150ms apart. + ``` + + @method throttle + @param {Object} [target] target of method to invoke + @param {Function|String} method The method to invoke. + May be a function or a string. If you pass a string + then it will be looked up on the passed target. + @param {Object} [args*] Optional arguments to pass to the timeout. + @param {Number} spacing Number of milliseconds to space out requests. + @return {void} +*/ +Ember.run.throttle = function() { + return backburner.throttle.apply(backburner, arguments); +}; + +// Make sure it's not an autorun during testing +function checkAutoRun() { + if (!Ember.run.currentRunLoop) { + Ember.assert("You have turned on testing mode, which disabled the run-loop's autorun. You will need to wrap any code with asynchronous side-effects in an Ember.run", !Ember.testing); + } +} + +})(); + + + +(function() { +// Ember.Logger +// get +// set +// guidFor, meta +// addObserver, removeObserver +// Ember.run.schedule +/** +@module ember-metal +*/ + +// .......................................................... +// CONSTANTS +// + +/** + Debug parameter you can turn on. This will log all bindings that fire to + the console. This should be disabled in production code. Note that you + can also enable this from the console or temporarily. + + @property LOG_BINDINGS + @for Ember + @type Boolean + @default false +*/ +Ember.LOG_BINDINGS = false || !!Ember.ENV.LOG_BINDINGS; + +var get = Ember.get, + set = Ember.set, + guidFor = Ember.guidFor, + IS_GLOBAL = /^([A-Z$]|([0-9][A-Z$]))/; + +/** + Returns true if the provided path is global (e.g., `MyApp.fooController.bar`) + instead of local (`foo.bar.baz`). + + @method isGlobalPath + @for Ember + @private + @param {String} path + @return Boolean +*/ +var isGlobalPath = Ember.isGlobalPath = function(path) { + return IS_GLOBAL.test(path); +}; + +function getWithGlobals(obj, path) { + return get(isGlobalPath(path) ? Ember.lookup : obj, path); +} + +// .......................................................... +// BINDING +// + +var Binding = function(toPath, fromPath) { + this._direction = 'fwd'; + this._from = fromPath; + this._to = toPath; + this._directionMap = Ember.Map.create(); +}; + +/** +@class Binding +@namespace Ember +*/ + +Binding.prototype = { + /** + This copies the Binding so it can be connected to another object. + + @method copy + @return {Ember.Binding} `this` + */ + copy: function () { + var copy = new Binding(this._to, this._from); + if (this._oneWay) { copy._oneWay = true; } + return copy; + }, + + // .......................................................... + // CONFIG + // + + /** + This will set `from` property path to the specified value. It will not + attempt to resolve this property path to an actual object until you + connect the binding. + + The binding will search for the property path starting at the root object + you pass when you `connect()` the binding. It follows the same rules as + `get()` - see that method for more information. + + @method from + @param {String} path the property path to connect to + @return {Ember.Binding} `this` + */ + from: function(path) { + this._from = path; + return this; + }, + + /** + This will set the `to` property path to the specified value. It will not + attempt to resolve this property path to an actual object until you + connect the binding. + + The binding will search for the property path starting at the root object + you pass when you `connect()` the binding. It follows the same rules as + `get()` - see that method for more information. + + @method to + @param {String|Tuple} path A property path or tuple + @return {Ember.Binding} `this` + */ + to: function(path) { + this._to = path; + return this; + }, + + /** + Configures the binding as one way. A one-way binding will relay changes + on the `from` side to the `to` side, but not the other way around. This + means that if you change the `to` side directly, the `from` side may have + a different value. + + @method oneWay + @return {Ember.Binding} `this` + */ + oneWay: function() { + this._oneWay = true; + return this; + }, + + /** + @method toString + @return {String} string representation of binding + */ + toString: function() { + var oneWay = this._oneWay ? '[oneWay]' : ''; + return "Ember.Binding<" + guidFor(this) + ">(" + this._from + " -> " + this._to + ")" + oneWay; + }, + + // .......................................................... + // CONNECT AND SYNC + // + + /** + Attempts to connect this binding instance so that it can receive and relay + changes. This method will raise an exception if you have not set the + from/to properties yet. + + @method connect + @param {Object} obj The root object for this binding. + @return {Ember.Binding} `this` + */ + connect: function(obj) { + Ember.assert('Must pass a valid object to Ember.Binding.connect()', !!obj); + + var fromPath = this._from, toPath = this._to; + Ember.trySet(obj, toPath, getWithGlobals(obj, fromPath)); + + // add an observer on the object to be notified when the binding should be updated + Ember.addObserver(obj, fromPath, this, this.fromDidChange); + + // if the binding is a two-way binding, also set up an observer on the target + if (!this._oneWay) { Ember.addObserver(obj, toPath, this, this.toDidChange); } + + this._readyToSync = true; + + return this; + }, + + /** + Disconnects the binding instance. Changes will no longer be relayed. You + will not usually need to call this method. + + @method disconnect + @param {Object} obj The root object you passed when connecting the binding. + @return {Ember.Binding} `this` + */ + disconnect: function(obj) { + Ember.assert('Must pass a valid object to Ember.Binding.disconnect()', !!obj); + + var twoWay = !this._oneWay; + + // remove an observer on the object so we're no longer notified of + // changes that should update bindings. + Ember.removeObserver(obj, this._from, this, this.fromDidChange); + + // if the binding is two-way, remove the observer from the target as well + if (twoWay) { Ember.removeObserver(obj, this._to, this, this.toDidChange); } + + this._readyToSync = false; // disable scheduled syncs... + return this; + }, + + // .......................................................... + // PRIVATE + // + + /* called when the from side changes */ + fromDidChange: function(target) { + this._scheduleSync(target, 'fwd'); + }, + + /* called when the to side changes */ + toDidChange: function(target) { + this._scheduleSync(target, 'back'); + }, + + _scheduleSync: function(obj, dir) { + var directionMap = this._directionMap; + var existingDir = directionMap.get(obj); + + // if we haven't scheduled the binding yet, schedule it + if (!existingDir) { + Ember.run.schedule('sync', this, this._sync, obj); + directionMap.set(obj, dir); + } + + // If both a 'back' and 'fwd' sync have been scheduled on the same object, + // default to a 'fwd' sync so that it remains deterministic. + if (existingDir === 'back' && dir === 'fwd') { + directionMap.set(obj, 'fwd'); + } + }, + + _sync: function(obj) { + var log = Ember.LOG_BINDINGS; + + // don't synchronize destroyed objects or disconnected bindings + if (obj.isDestroyed || !this._readyToSync) { return; } + + // get the direction of the binding for the object we are + // synchronizing from + var directionMap = this._directionMap; + var direction = directionMap.get(obj); + + var fromPath = this._from, toPath = this._to; + + directionMap.remove(obj); + + // if we're synchronizing from the remote object... + if (direction === 'fwd') { + var fromValue = getWithGlobals(obj, this._from); + if (log) { + Ember.Logger.log(' ', this.toString(), '->', fromValue, obj); + } + if (this._oneWay) { + Ember.trySet(obj, toPath, fromValue); + } else { + Ember._suspendObserver(obj, toPath, this, this.toDidChange, function () { + Ember.trySet(obj, toPath, fromValue); + }); + } + // if we're synchronizing *to* the remote object + } else if (direction === 'back') { + var toValue = get(obj, this._to); + if (log) { + Ember.Logger.log(' ', this.toString(), '<-', toValue, obj); + } + Ember._suspendObserver(obj, fromPath, this, this.fromDidChange, function () { + Ember.trySet(Ember.isGlobalPath(fromPath) ? Ember.lookup : obj, fromPath, toValue); + }); + } + } + +}; + +function mixinProperties(to, from) { + for (var key in from) { + if (from.hasOwnProperty(key)) { + to[key] = from[key]; + } + } +} + +mixinProperties(Binding, { + + /* + See `Ember.Binding.from`. + + @method from + @static + */ + from: function() { + var C = this, binding = new C(); + return binding.from.apply(binding, arguments); + }, + + /* + See `Ember.Binding.to`. + + @method to + @static + */ + to: function() { + var C = this, binding = new C(); + return binding.to.apply(binding, arguments); + }, + + /** + Creates a new Binding instance and makes it apply in a single direction. + A one-way binding will relay changes on the `from` side object (supplied + as the `from` argument) the `to` side, but not the other way around. + This means that if you change the "to" side directly, the "from" side may have + a different value. + + See `Binding.oneWay`. + + @method oneWay + @param {String} from from path. + @param {Boolean} [flag] (Optional) passing nothing here will make the + binding `oneWay`. You can instead pass `false` to disable `oneWay`, making the + binding two way again. + @return {Ember.Binding} `this` + */ + oneWay: function(from, flag) { + var C = this, binding = new C(null, from); + return binding.oneWay(flag); + } + +}); + +/** + An `Ember.Binding` connects the properties of two objects so that whenever + the value of one property changes, the other property will be changed also. + + ## Automatic Creation of Bindings with `/^*Binding/`-named Properties + + You do not usually create Binding objects directly but instead describe + bindings in your class or object definition using automatic binding + detection. + + Properties ending in a `Binding` suffix will be converted to `Ember.Binding` + instances. The value of this property should be a string representing a path + to another object or a custom binding instanced created using Binding helpers + (see "One Way Bindings"): + + ``` + valueBinding: "MyApp.someController.title" + ``` + + This will create a binding from `MyApp.someController.title` to the `value` + property of your object instance automatically. Now the two values will be + kept in sync. + + ## One Way Bindings + + One especially useful binding customization you can use is the `oneWay()` + helper. This helper tells Ember that you are only interested in + receiving changes on the object you are binding from. For example, if you + are binding to a preference and you want to be notified if the preference + has changed, but your object will not be changing the preference itself, you + could do: + + ``` + bigTitlesBinding: Ember.Binding.oneWay("MyApp.preferencesController.bigTitles") + ``` + + This way if the value of `MyApp.preferencesController.bigTitles` changes the + `bigTitles` property of your object will change also. However, if you + change the value of your `bigTitles` property, it will not update the + `preferencesController`. + + One way bindings are almost twice as fast to setup and twice as fast to + execute because the binding only has to worry about changes to one side. + + You should consider using one way bindings anytime you have an object that + may be created frequently and you do not intend to change a property; only + to monitor it for changes (such as in the example above). + + ## Adding Bindings Manually + + All of the examples above show you how to configure a custom binding, but the + result of these customizations will be a binding template, not a fully active + Binding instance. The binding will actually become active only when you + instantiate the object the binding belongs to. It is useful however, to + understand what actually happens when the binding is activated. + + For a binding to function it must have at least a `from` property and a `to` + property. The `from` property path points to the object/key that you want to + bind from while the `to` path points to the object/key you want to bind to. + + When you define a custom binding, you are usually describing the property + you want to bind from (such as `MyApp.someController.value` in the examples + above). When your object is created, it will automatically assign the value + you want to bind `to` based on the name of your binding key. In the + examples above, during init, Ember objects will effectively call + something like this on your binding: + + ```javascript + binding = Ember.Binding.from(this.valueBinding).to("value"); + ``` + + This creates a new binding instance based on the template you provide, and + sets the to path to the `value` property of the new object. Now that the + binding is fully configured with a `from` and a `to`, it simply needs to be + connected to become active. This is done through the `connect()` method: + + ```javascript + binding.connect(this); + ``` + + Note that when you connect a binding you pass the object you want it to be + connected to. This object will be used as the root for both the from and + to side of the binding when inspecting relative paths. This allows the + binding to be automatically inherited by subclassed objects as well. + + Now that the binding is connected, it will observe both the from and to side + and relay changes. + + If you ever needed to do so (you almost never will, but it is useful to + understand this anyway), you could manually create an active binding by + using the `Ember.bind()` helper method. (This is the same method used by + to setup your bindings on objects): + + ```javascript + Ember.bind(MyApp.anotherObject, "value", "MyApp.someController.value"); + ``` + + Both of these code fragments have the same effect as doing the most friendly + form of binding creation like so: + + ```javascript + MyApp.anotherObject = Ember.Object.create({ + valueBinding: "MyApp.someController.value", + + // OTHER CODE FOR THIS OBJECT... + }); + ``` + + Ember's built in binding creation method makes it easy to automatically + create bindings for you. You should always use the highest-level APIs + available, even if you understand how it works underneath. + + @class Binding + @namespace Ember + @since Ember 0.9 +*/ +Ember.Binding = Binding; + + +/** + Global helper method to create a new binding. Just pass the root object + along with a `to` and `from` path to create and connect the binding. + + @method bind + @for Ember + @param {Object} obj The root object of the transform. + @param {String} to The path to the 'to' side of the binding. + Must be relative to obj. + @param {String} from The path to the 'from' side of the binding. + Must be relative to obj or a global path. + @return {Ember.Binding} binding instance +*/ +Ember.bind = function(obj, to, from) { + return new Ember.Binding(to, from).connect(obj); +}; + +/** + @method oneWay + @for Ember + @param {Object} obj The root object of the transform. + @param {String} to The path to the 'to' side of the binding. + Must be relative to obj. + @param {String} from The path to the 'from' side of the binding. + Must be relative to obj or a global path. + @return {Ember.Binding} binding instance +*/ +Ember.oneWay = function(obj, to, from) { + return new Ember.Binding(to, from).oneWay().connect(obj); +}; + +})(); + + + +(function() { +/** +@module ember +@submodule ember-metal +*/ + +var Mixin, REQUIRED, Alias, + a_map = Ember.ArrayPolyfills.map, + a_indexOf = Ember.ArrayPolyfills.indexOf, + a_forEach = Ember.ArrayPolyfills.forEach, + a_slice = [].slice, + o_create = Ember.create, + defineProperty = Ember.defineProperty, + guidFor = Ember.guidFor; + +function mixinsMeta(obj) { + var m = Ember.meta(obj, true), ret = m.mixins; + if (!ret) { + ret = m.mixins = {}; + } else if (!m.hasOwnProperty('mixins')) { + ret = m.mixins = o_create(ret); + } + return ret; +} + +function initMixin(mixin, args) { + if (args && args.length > 0) { + mixin.mixins = a_map.call(args, function(x) { + if (x instanceof Mixin) { return x; } + + // Note: Manually setup a primitive mixin here. This is the only + // way to actually get a primitive mixin. This way normal creation + // of mixins will give you combined mixins... + var mixin = new Mixin(); + mixin.properties = x; + return mixin; + }); + } + return mixin; +} + +function isMethod(obj) { + return 'function' === typeof obj && + obj.isMethod !== false && + obj !== Boolean && obj !== Object && obj !== Number && obj !== Array && obj !== Date && obj !== String; +} + +var CONTINUE = {}; + +function mixinProperties(mixinsMeta, mixin) { + var guid; + + if (mixin instanceof Mixin) { + guid = guidFor(mixin); + if (mixinsMeta[guid]) { return CONTINUE; } + mixinsMeta[guid] = mixin; + return mixin.properties; + } else { + return mixin; // apply anonymous mixin properties + } +} + +function concatenatedMixinProperties(concatProp, props, values, base) { + var concats; + + // reset before adding each new mixin to pickup concats from previous + concats = values[concatProp] || base[concatProp]; + if (props[concatProp]) { + concats = concats ? concats.concat(props[concatProp]) : props[concatProp]; + } + + return concats; +} + +function giveDescriptorSuper(meta, key, property, values, descs) { + var superProperty; + + // Computed properties override methods, and do not call super to them + if (values[key] === undefined) { + // Find the original descriptor in a parent mixin + superProperty = descs[key]; + } + + // If we didn't find the original descriptor in a parent mixin, find + // it on the original object. + superProperty = superProperty || meta.descs[key]; + + if (!superProperty || !(superProperty instanceof Ember.ComputedProperty)) { + return property; + } + + // Since multiple mixins may inherit from the same parent, we need + // to clone the computed property so that other mixins do not receive + // the wrapped version. + property = o_create(property); + property.func = Ember.wrap(property.func, superProperty.func); + + return property; +} + +function giveMethodSuper(obj, key, method, values, descs) { + var superMethod; + + // Methods overwrite computed properties, and do not call super to them. + if (descs[key] === undefined) { + // Find the original method in a parent mixin + superMethod = values[key]; + } + + // If we didn't find the original value in a parent mixin, find it in + // the original object + superMethod = superMethod || obj[key]; + + // Only wrap the new method if the original method was a function + if ('function' !== typeof superMethod) { + return method; + } + + return Ember.wrap(method, superMethod); +} + +function applyConcatenatedProperties(obj, key, value, values) { + var baseValue = values[key] || obj[key]; + + if (baseValue) { + if ('function' === typeof baseValue.concat) { + return baseValue.concat(value); + } else { + return Ember.makeArray(baseValue).concat(value); + } + } else { + return Ember.makeArray(value); + } +} + +function applyMergedProperties(obj, key, value, values) { + var baseValue = values[key] || obj[key]; + + if (!baseValue) { return value; } + + var newBase = Ember.merge({}, baseValue); + for (var prop in value) { + if (!value.hasOwnProperty(prop)) { continue; } + + var propValue = value[prop]; + if (isMethod(propValue)) { + // TODO: support for Computed Properties, etc? + newBase[prop] = giveMethodSuper(obj, prop, propValue, baseValue, {}); + } else { + newBase[prop] = propValue; + } + } + + return newBase; +} + +function addNormalizedProperty(base, key, value, meta, descs, values, concats, mergings) { + if (value instanceof Ember.Descriptor) { + if (value === REQUIRED && descs[key]) { return CONTINUE; } + + // Wrap descriptor function to implement + // _super() if needed + if (value.func) { + value = giveDescriptorSuper(meta, key, value, values, descs); + } + + descs[key] = value; + values[key] = undefined; + } else { + if ((concats && a_indexOf.call(concats, key) >= 0) || + key === 'concatenatedProperties' || + key === 'mergedProperties') { + value = applyConcatenatedProperties(base, key, value, values); + } else if ((mergings && a_indexOf.call(mergings, key) >= 0)) { + value = applyMergedProperties(base, key, value, values); + } else if (isMethod(value)) { + value = giveMethodSuper(base, key, value, values, descs); + } + + descs[key] = undefined; + values[key] = value; + } +} + +function mergeMixins(mixins, m, descs, values, base, keys) { + var mixin, props, key, concats, mergings, meta; + + function removeKeys(keyName) { + delete descs[keyName]; + delete values[keyName]; + } + + for(var i=0, l=mixins.length; i= 0) { + if (_detect(mixins[loc], targetMixin, seen)) { return true; } + } + return false; +} + +/** + @method detect + @param obj + @return {Boolean} +*/ +MixinPrototype.detect = function(obj) { + if (!obj) { return false; } + if (obj instanceof Mixin) { return _detect(obj, this, {}); } + var mixins = Ember.meta(obj, false).mixins; + if (mixins) { + return !!mixins[guidFor(this)]; + } + return false; +}; + +MixinPrototype.without = function() { + var ret = new Mixin(this); + ret._without = a_slice.call(arguments); + return ret; +}; + +function _keys(ret, mixin, seen) { + if (seen[guidFor(mixin)]) { return; } + seen[guidFor(mixin)] = true; + + if (mixin.properties) { + var props = mixin.properties; + for (var key in props) { + if (props.hasOwnProperty(key)) { ret[key] = true; } + } + } else if (mixin.mixins) { + a_forEach.call(mixin.mixins, function(x) { _keys(ret, x, seen); }); + } +} + +MixinPrototype.keys = function() { + var keys = {}, seen = {}, ret = []; + _keys(keys, this, seen); + for(var key in keys) { + if (keys.hasOwnProperty(key)) { ret.push(key); } + } + return ret; +}; + +// returns the mixins currently applied to the specified object +// TODO: Make Ember.mixin +Mixin.mixins = function(obj) { + var mixins = Ember.meta(obj, false).mixins, ret = []; + + if (!mixins) { return ret; } + + for (var key in mixins) { + var mixin = mixins[key]; + + // skip primitive mixins since these are always anonymous + if (!mixin.properties) { ret.push(mixin); } + } + + return ret; +}; + +REQUIRED = new Ember.Descriptor(); +REQUIRED.toString = function() { return '(Required Property)'; }; + +/** + Denotes a required property for a mixin + + @method required + @for Ember +*/ +Ember.required = function() { + return REQUIRED; +}; + +Alias = function(methodName) { + this.methodName = methodName; +}; +Alias.prototype = new Ember.Descriptor(); + +/** + Makes a property or method available via an additional name. + + ```javascript + App.PaintSample = Ember.Object.extend({ + color: 'red', + colour: Ember.alias('color'), + name: function() { + return "Zed"; + }, + moniker: Ember.alias("name") + }); + + var paintSample = App.PaintSample.create() + paintSample.get('colour'); // 'red' + paintSample.moniker(); // 'Zed' + ``` + + @method alias + @for Ember + @param {String} methodName name of the method or property to alias + @return {Ember.Descriptor} + @deprecated Use `Ember.aliasMethod` or `Ember.computed.alias` instead +*/ +Ember.alias = function(methodName) { + Ember.deprecate("Ember.alias is deprecated. Please use Ember.aliasMethod or Ember.computed.alias instead."); + return new Alias(methodName); +}; + +/** + Makes a method available via an additional name. + + ```javascript + App.Person = Ember.Object.extend({ + name: function() { + return 'Tomhuda Katzdale'; + }, + moniker: Ember.aliasMethod('name') + }); + + var goodGuy = App.Person.create() + ``` + + @method aliasMethod + @for Ember + @param {String} methodName name of the method to alias + @return {Ember.Descriptor} +*/ +Ember.aliasMethod = function(methodName) { + return new Alias(methodName); +}; + +// .......................................................... +// OBSERVER HELPER +// + +/** + Specify a method that observes property changes. + + ```javascript + Ember.Object.extend({ + valueObserver: Ember.observer('value', function() { + // Executes whenever the "value" property changes + }) + }); + ``` + + In the future this method may become asynchronous. If you want to ensure + synchronous behavior, use `immediateObserver`. + + Also available as `Function.prototype.observes` if prototype extensions are + enabled. + + @method observer + @for Ember + @param {String} propertyNames* + @param {Function} func + @return func +*/ +Ember.observer = function() { + var func = a_slice.call(arguments, -1)[0]; + var paths = a_slice.call(arguments, 0, -1); + + if (typeof func !== "function") { + // revert to old, soft-deprecated argument ordering + + func = arguments[0]; + paths = a_slice.call(arguments, 1); + } + + if (typeof func !== "function") { + throw new Ember.Error("Ember.observer called without a function"); + } + + func.__ember_observes__ = paths; + return func; +}; + +/** + Specify a method that observes property changes. + + ```javascript + Ember.Object.extend({ + valueObserver: Ember.immediateObserver('value', function() { + // Executes whenever the "value" property changes + }) + }); + ``` + + In the future, `Ember.observer` may become asynchronous. In this event, + `Ember.immediateObserver` will maintain the synchronous behavior. + + Also available as `Function.prototype.observesImmediately` if prototype extensions are + enabled. + + @method immediateObserver + @for Ember + @param {String} propertyNames* + @param {Function} func + @return func +*/ +Ember.immediateObserver = function() { + for (var i=0, l=arguments.length; i this.changingFrom ? 'green' : 'red'; + // logic + } + }), + + friendsDidChange: Ember.observer('friends.@each.name', function(obj, keyName) { + // some logic + // obj.get(keyName) returns friends array + }) + }); + ``` + + Also available as `Function.prototype.observesBefore` if prototype extensions are + enabled. + + @method beforeObserver + @for Ember + @param {String} propertyNames* + @param {Function} func + @return func +*/ +Ember.beforeObserver = function() { + var func = a_slice.call(arguments, -1)[0]; + var paths = a_slice.call(arguments, 0, -1); + + if (typeof func !== "function") { + // revert to old, soft-deprecated argument ordering + + func = arguments[0]; + paths = a_slice.call(arguments, 1); + } + + if (typeof func !== "function") { + throw new Ember.Error("Ember.beforeObserver called without a function"); + } + + func.__ember_observesBefore__ = paths; + return func; +}; + +})(); + + + +(function() { +// Provides a way to register library versions with ember. +var forEach = Ember.EnumerableUtils.forEach, + indexOf = Ember.EnumerableUtils.indexOf; + +Ember.libraries = function() { + var libraries = []; + var coreLibIndex = 0; + + var getLibrary = function(name) { + for (var i = 0; i < libraries.length; i++) { + if (libraries[i].name === name) { + return libraries[i]; + } + } + }; + + libraries.register = function(name, version) { + if (!getLibrary(name)) { + libraries.push({name: name, version: version}); + } + }; + + libraries.registerCoreLibrary = function(name, version) { + if (!getLibrary(name)) { + libraries.splice(coreLibIndex++, 0, {name: name, version: version}); + } + }; + + libraries.deRegister = function(name) { + var lib = getLibrary(name); + if (lib) libraries.splice(indexOf(libraries, lib), 1); + }; + + libraries.each = function (callback) { + forEach(libraries, function(lib) { + callback(lib.name, lib.version); + }); + }; + + return libraries; +}(); + +Ember.libraries.registerCoreLibrary('Ember', Ember.VERSION); + +})(); + + + +(function() { +/** +Ember Metal + +@module ember +@submodule ember-metal +*/ + +})(); + +(function() { +define("rsvp/all", + ["rsvp/promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__.Promise; + /* global toString */ + + + function all(promises) { + if (Object.prototype.toString.call(promises) !== "[object Array]") { + throw new TypeError('You must pass an array to all.'); + } + + return new Promise(function(resolve, reject) { + var results = [], remaining = promises.length, + promise; + + if (remaining === 0) { + resolve([]); + } + + function resolver(index) { + return function(value) { + resolveAll(index, value); + }; + } + + function resolveAll(index, value) { + results[index] = value; + if (--remaining === 0) { + resolve(results); + } + } + + for (var i = 0; i < promises.length; i++) { + promise = promises[i]; + + if (promise && typeof promise.then === 'function') { + promise.then(resolver(i), reject); + } else { + resolveAll(i, promise); + } + } + }); + } + + + __exports__.all = all; + }); +define("rsvp/async", + ["exports"], + function(__exports__) { + "use strict"; + var browserGlobal = (typeof window !== 'undefined') ? window : {}; + var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver; + var async; + var local = (typeof global !== 'undefined') ? global : this; + + // old node + function useNextTick() { + return function(callback, arg) { + process.nextTick(function() { + callback(arg); + }); + }; + } + + // node >= 0.10.x + function useSetImmediate() { + return function(callback, arg) { + /* global setImmediate */ + setImmediate(function(){ + callback(arg); + }); + }; + } + + function useMutationObserver() { + var queue = []; + + var observer = new BrowserMutationObserver(function() { + var toProcess = queue.slice(); + queue = []; + + toProcess.forEach(function(tuple) { + var callback = tuple[0], arg= tuple[1]; + callback(arg); + }); + }); + + var element = document.createElement('div'); + observer.observe(element, { attributes: true }); + + // Chrome Memory Leak: https://bugs.webkit.org/show_bug.cgi?id=93661 + window.addEventListener('unload', function(){ + observer.disconnect(); + observer = null; + }, false); + + return function(callback, arg) { + queue.push([callback, arg]); + element.setAttribute('drainQueue', 'drainQueue'); + }; + } + + function useSetTimeout() { + return function(callback, arg) { + local.setTimeout(function() { + callback(arg); + }, 1); + }; + } + + if (typeof setImmediate === 'function') { + async = useSetImmediate(); + } else if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') { + async = useNextTick(); + } else if (BrowserMutationObserver) { + async = useMutationObserver(); + } else { + async = useSetTimeout(); + } + + + __exports__.async = async; + }); +define("rsvp/config", + ["rsvp/async","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var async = __dependency1__.async; + + var config = {}; + config.async = async; + + + __exports__.config = config; + }); +define("rsvp/defer", + ["rsvp/promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__.Promise; + + function defer() { + var deferred = { + // pre-allocate shape + resolve: undefined, + reject: undefined, + promise: undefined + }; + + deferred.promise = new Promise(function(resolve, reject) { + deferred.resolve = resolve; + deferred.reject = reject; + }); + + return deferred; + } + + + __exports__.defer = defer; + }); +define("rsvp/events", + ["exports"], + function(__exports__) { + "use strict"; + var Event = function(type, options) { + this.type = type; + + for (var option in options) { + if (!options.hasOwnProperty(option)) { continue; } + + this[option] = options[option]; + } + }; + + var indexOf = function(callbacks, callback) { + for (var i=0, l=callbacks.length; i 2) { + resolve(Array.prototype.slice.call(arguments, 1)); + } else { + resolve(value); + } + }; + } + + function denodeify(nodeFunc) { + return function() { + var nodeArgs = Array.prototype.slice.call(arguments), resolve, reject; + var thisArg = this; + + var promise = new Promise(function(nodeResolve, nodeReject) { + resolve = nodeResolve; + reject = nodeReject; + }); + + all(nodeArgs).then(function(nodeArgs) { + nodeArgs.push(makeNodeCallbackFor(resolve, reject)); + + try { + nodeFunc.apply(thisArg, nodeArgs); + } catch(e) { + reject(e); + } + }); + + return promise; + }; + } + + + __exports__.denodeify = denodeify; + }); +define("rsvp/promise", + ["rsvp/config","rsvp/events","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var config = __dependency1__.config; + var EventTarget = __dependency2__.EventTarget; + + function objectOrFunction(x) { + return isFunction(x) || (typeof x === "object" && x !== null); + } + + function isFunction(x){ + return typeof x === "function"; + } + + var Promise = function(resolver) { + var promise = this, + resolved = false; + + if (typeof resolver !== 'function') { + throw new TypeError('You must pass a resolver function as the sole argument to the promise constructor'); + } + + if (!(promise instanceof Promise)) { + return new Promise(resolver); + } + + var resolvePromise = function(value) { + if (resolved) { return; } + resolved = true; + resolve(promise, value); + }; + + var rejectPromise = function(value) { + if (resolved) { return; } + resolved = true; + reject(promise, value); + }; + + this.on('promise:resolved', function(event) { + this.trigger('success', { detail: event.detail }); + }, this); + + this.on('promise:failed', function(event) { + this.trigger('error', { detail: event.detail }); + }, this); + + this.on('error', onerror); + + try { + resolver(resolvePromise, rejectPromise); + } catch(e) { + rejectPromise(e); + } + }; + + function onerror(event) { + if (config.onerror) { + config.onerror(event.detail); + } + } + + var invokeCallback = function(type, promise, callback, event) { + var hasCallback = isFunction(callback), + value, error, succeeded, failed; + + if (hasCallback) { + try { + value = callback(event.detail); + succeeded = true; + } catch(e) { + failed = true; + error = e; + } + } else { + value = event.detail; + succeeded = true; + } + + if (handleThenable(promise, value)) { + return; + } else if (hasCallback && succeeded) { + resolve(promise, value); + } else if (failed) { + reject(promise, error); + } else if (type === 'resolve') { + resolve(promise, value); + } else if (type === 'reject') { + reject(promise, value); + } + }; + + Promise.prototype = { + constructor: Promise, + + isRejected: undefined, + isFulfilled: undefined, + rejectedReason: undefined, + fulfillmentValue: undefined, + + then: function(done, fail) { + this.off('error', onerror); + + var thenPromise = new this.constructor(function() {}); + + if (this.isFulfilled) { + config.async(function(promise) { + invokeCallback('resolve', thenPromise, done, { detail: promise.fulfillmentValue }); + }, this); + } + + if (this.isRejected) { + config.async(function(promise) { + invokeCallback('reject', thenPromise, fail, { detail: promise.rejectedReason }); + }, this); + } + + this.on('promise:resolved', function(event) { + invokeCallback('resolve', thenPromise, done, event); + }); + + this.on('promise:failed', function(event) { + invokeCallback('reject', thenPromise, fail, event); + }); + + return thenPromise; + }, + + fail: function(fail) { + return this.then(null, fail); + } + }; + + EventTarget.mixin(Promise.prototype); + + function resolve(promise, value) { + if (promise === value) { + fulfill(promise, value); + } else if (!handleThenable(promise, value)) { + fulfill(promise, value); + } + } + + function handleThenable(promise, value) { + var then = null, + resolved; + + try { + if (promise === value) { + throw new TypeError("A promises callback cannot return that same promise."); + } + + if (objectOrFunction(value)) { + then = value.then; + + if (isFunction(then)) { + then.call(value, function(val) { + if (resolved) { return true; } + resolved = true; + + if (value !== val) { + resolve(promise, val); + } else { + fulfill(promise, val); + } + }, function(val) { + if (resolved) { return true; } + resolved = true; + + reject(promise, val); + }); + + return true; + } + } + } catch (error) { + reject(promise, error); + return true; + } + + return false; + } + + function fulfill(promise, value) { + config.async(function() { + promise.trigger('promise:resolved', { detail: value }); + promise.isFulfilled = true; + promise.fulfillmentValue = value; + }); + } + + function reject(promise, value) { + config.async(function() { + promise.trigger('promise:failed', { detail: value }); + promise.isRejected = true; + promise.rejectedReason = value; + }); + } + + + __exports__.Promise = Promise; + }); +define("rsvp/reject", + ["rsvp/promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__.Promise; + + function reject(reason) { + return new Promise(function (resolve, reject) { + reject(reason); + }); + } + + + __exports__.reject = reject; + }); +define("rsvp/resolve", + ["rsvp/promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__.Promise; + + function resolve(thenable) { + return new Promise(function(resolve, reject) { + resolve(thenable); + }); + } + + + __exports__.resolve = resolve; + }); +define("rsvp/rethrow", + ["exports"], + function(__exports__) { + "use strict"; + var local = (typeof global === "undefined") ? this : global; + + function rethrow(reason) { + local.setTimeout(function() { + throw reason; + }); + throw reason; + } + + + __exports__.rethrow = rethrow; + }); +define("rsvp", + ["rsvp/events","rsvp/promise","rsvp/node","rsvp/all","rsvp/hash","rsvp/rethrow","rsvp/defer","rsvp/config","rsvp/resolve","rsvp/reject","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) { + "use strict"; + var EventTarget = __dependency1__.EventTarget; + var Promise = __dependency2__.Promise; + var denodeify = __dependency3__.denodeify; + var all = __dependency4__.all; + var hash = __dependency5__.hash; + var rethrow = __dependency6__.rethrow; + var defer = __dependency7__.defer; + var config = __dependency8__.config; + var resolve = __dependency9__.resolve; + var reject = __dependency10__.reject; + + function configure(name, value) { + config[name] = value; + } + + + __exports__.Promise = Promise; + __exports__.EventTarget = EventTarget; + __exports__.all = all; + __exports__.hash = hash; + __exports__.rethrow = rethrow; + __exports__.defer = defer; + __exports__.denodeify = denodeify; + __exports__.configure = configure; + __exports__.resolve = resolve; + __exports__.reject = reject; + }); +})(); + +(function() { +/** +@private +Public api for the container is still in flux. +The public api, specified on the application namespace should be considered the stable api. +// @module container +*/ + +/* + Flag to enable/disable model factory injections (disabled by default) + If model factory injections are enabled, models should not be + accessed globally (only through `container.lookupFactory('model:modelName'))`); +*/ +Ember.MODEL_FACTORY_INJECTIONS = false || !!Ember.ENV.MODEL_FACTORY_INJECTIONS; + +define("container", + [], + function() { + + // A safe and simple inheriting object. + function InheritingDict(parent) { + this.parent = parent; + this.dict = {}; + } + + InheritingDict.prototype = { + + /** + @property parent + @type InheritingDict + @default null + */ + + parent: null, + + /** + Object used to store the current nodes data. + + @property dict + @type Object + @default Object + */ + dict: null, + + /** + Retrieve the value given a key, if the value is present at the current + level use it, otherwise walk up the parent hierarchy and try again. If + no matching key is found, return undefined. + + @method get + @return {any} + */ + get: function(key) { + var dict = this.dict; + + if (dict.hasOwnProperty(key)) { + return dict[key]; + } + + if (this.parent) { + return this.parent.get(key); + } + }, + + /** + Set the given value for the given key, at the current level. + + @method set + @param {String} key + @param {Any} value + */ + set: function(key, value) { + this.dict[key] = value; + }, + + /** + Delete the given key + + @method remove + @param {String} key + */ + remove: function(key) { + delete this.dict[key]; + }, + + /** + Check for the existence of given a key, if the key is present at the current + level return true, otherwise walk up the parent hierarchy and try again. If + no matching key is found, return false. + + @method has + @param {String} key + @return {Boolean} + */ + has: function(key) { + var dict = this.dict; + + if (dict.hasOwnProperty(key)) { + return true; + } + + if (this.parent) { + return this.parent.has(key); + } + + return false; + }, + + /** + Iterate and invoke a callback for each local key-value pair. + + @method eachLocal + @param {Function} callback + @param {Object} binding + */ + eachLocal: function(callback, binding) { + var dict = this.dict; + + for (var prop in dict) { + if (dict.hasOwnProperty(prop)) { + callback.call(binding, prop, dict[prop]); + } + } + } + }; + + + // A lightweight container that helps to assemble and decouple components. + // Public api for the container is still in flux. + // The public api, specified on the application namespace should be considered the stable api. + function Container(parent) { + this.parent = parent; + this.children = []; + + this.resolver = parent && parent.resolver || function() {}; + + this.registry = new InheritingDict(parent && parent.registry); + this.cache = new InheritingDict(parent && parent.cache); + this.factoryCache = new InheritingDict(parent && parent.cache); + this.typeInjections = new InheritingDict(parent && parent.typeInjections); + this.injections = {}; + + this.factoryTypeInjections = new InheritingDict(parent && parent.factoryTypeInjections); + this.factoryInjections = {}; + + this._options = new InheritingDict(parent && parent._options); + this._typeOptions = new InheritingDict(parent && parent._typeOptions); + } + + Container.prototype = { + + /** + @property parent + @type Container + @default null + */ + parent: null, + + /** + @property children + @type Array + @default [] + */ + children: null, + + /** + @property resolver + @type function + */ + resolver: null, + + /** + @property registry + @type InheritingDict + */ + registry: null, + + /** + @property cache + @type InheritingDict + */ + cache: null, + + /** + @property typeInjections + @type InheritingDict + */ + typeInjections: null, + + /** + @property injections + @type Object + @default {} + */ + injections: null, + + /** + @private + + @property _options + @type InheritingDict + @default null + */ + _options: null, + + /** + @private + + @property _typeOptions + @type InheritingDict + */ + _typeOptions: null, + + /** + Returns a new child of the current container. These children are configured + to correctly inherit from the current container. + + @method child + @return {Container} + */ + child: function() { + var container = new Container(this); + this.children.push(container); + return container; + }, + + /** + Sets a key-value pair on the current container. If a parent container, + has the same key, once set on a child, the parent and child will diverge + as expected. + + @method set + @param {Object} object + @param {String} key + @param {any} value + */ + set: function(object, key, value) { + object[key] = value; + }, + + /** + Registers a factory for later injection. + + Example: + + ```javascript + var container = new Container(); + + container.register('model:user', Person, {singleton: false }); + container.register('fruit:favorite', Orange); + container.register('communication:main', Email, {singleton: false}); + ``` + + @method register + @param {String} fullName + @param {Function} factory + @param {Object} options + */ + register: function(fullName, factory, options) { + if (fullName.indexOf(':') === -1) { + throw new TypeError("malformed fullName, expected: `type:name` got: " + fullName + ""); + } + + if (factory === undefined) { + throw new TypeError('Attempting to register an unknown factory: `' + fullName + '`'); + } + + var normalizedName = this.normalize(fullName); + + if (this.cache.has(normalizedName)) { + throw new Error('Cannot re-register: `' + fullName +'`, as it has already been looked up.'); + } + + this.registry.set(normalizedName, factory); + this._options.set(normalizedName, options || {}); + }, + + /** + Unregister a fullName + + ```javascript + var container = new Container(); + container.register('model:user', User); + + container.lookup('model:user') instanceof User //=> true + + container.unregister('model:user') + container.lookup('model:user') === undefined //=> true + ``` + + @method unregister + @param {String} fullName + */ + unregister: function(fullName) { + var normalizedName = this.normalize(fullName); + + this.registry.remove(normalizedName); + this.cache.remove(normalizedName); + this.factoryCache.remove(normalizedName); + this._options.remove(normalizedName); + }, + + /** + Given a fullName return the corresponding factory. + + By default `resolve` will retrieve the factory from + its container's registry. + + ```javascript + var container = new Container(); + container.register('api:twitter', Twitter); + + container.resolve('api:twitter') // => Twitter + ``` + + Optionally the container can be provided with a custom resolver. + If provided, `resolve` will first provide the custom resolver + the oppertunity to resolve the fullName, otherwise it will fallback + to the registry. + + ```javascript + var container = new Container(); + container.resolver = function(fullName) { + // lookup via the module system of choice + }; + + // the twitter factory is added to the module system + container.resolve('api:twitter') // => Twitter + ``` + + @method resolve + @param {String} fullName + @return {Function} fullName's factory + */ + resolve: function(fullName) { + return this.resolver(fullName) || this.registry.get(fullName); + }, + + /** + A hook that can be used to describe how the resolver will + attempt to find the factory. + + For example, the default Ember `.describe` returns the full + class name (including namespace) where Ember's resolver expects + to find the `fullName`. + + @method describe + */ + describe: function(fullName) { + return fullName; + }, + + /** + A hook to enable custom fullName normalization behaviour + + @method normalize + @param {String} fullName + @return {string} normalized fullName + */ + normalize: function(fullName) { + return fullName; + }, + + /** + @method makeToString + + @param {any} factory + @param {string} fullName + @return {function} toString function + */ + makeToString: function(factory, fullName) { + return factory.toString(); + }, + + /** + Given a fullName return a corresponding instance. + + The default behaviour is for lookup to return a singleton instance. + The singleton is scoped to the container, allowing multiple containers + to all have their own locally scoped singletons. + + ```javascript + var container = new Container(); + container.register('api:twitter', Twitter); + + var twitter = container.lookup('api:twitter'); + + twitter instanceof Twitter; // => true + + // by default the container will return singletons + twitter2 = container.lookup('api:twitter'); + twitter instanceof Twitter; // => true + + twitter === twitter2; //=> true + ``` + + If singletons are not wanted an optional flag can be provided at lookup. + + ```javascript + var container = new Container(); + container.register('api:twitter', Twitter); + + var twitter = container.lookup('api:twitter', { singleton: false }); + var twitter2 = container.lookup('api:twitter', { singleton: false }); + + twitter === twitter2; //=> false + ``` + + @method lookup + @param {String} fullName + @param {Object} options + @return {any} + */ + lookup: function(fullName, options) { + fullName = this.normalize(fullName); + + options = options || {}; + + if (this.cache.has(fullName) && options.singleton !== false) { + return this.cache.get(fullName); + } + + var value = instantiate(this, fullName); + + if (value === undefined) { return; } + + if (isSingleton(this, fullName) && options.singleton !== false) { + this.cache.set(fullName, value); + } + + return value; + }, + + /** + Given a fullName return the corresponding factory. + + @method lookupFactory + @param {String} fullName + @return {any} + */ + lookupFactory: function(fullName) { + return factoryFor(this, fullName); + }, + + /** + Given a fullName check if the container is aware of its factory + or singleton instance. + + @method has + @param {String} fullName + @return {Boolean} + */ + has: function(fullName) { + if (this.cache.has(fullName)) { + return true; + } + + return !!factoryFor(this, fullName); + }, + + /** + Allow registering options for all factories of a type. + + ```javascript + var container = new Container(); + + // if all of type `connection` must not be singletons + container.optionsForType('connection', { singleton: false }); + + container.register('connection:twitter', TwitterConnection); + container.register('connection:facebook', FacebookConnection); + + var twitter = container.lookup('connection:twitter'); + var twitter2 = container.lookup('connection:twitter'); + + twitter === twitter2; // => false + + var facebook = container.lookup('connection:facebook'); + var facebook2 = container.lookup('connection:facebook'); + + facebook === facebook2; // => false + ``` + + @method optionsForType + @param {String} type + @param {Object} options + */ + optionsForType: function(type, options) { + if (this.parent) { illegalChildOperation('optionsForType'); } + + this._typeOptions.set(type, options); + }, + + /** + @method options + @param {String} type + @param {Object} options + */ + options: function(type, options) { + this.optionsForType(type, options); + }, + + /** + @private + + Used only via `injection`. + + Provides a specialized form of injection, specifically enabling + all objects of one type to be injected with a reference to another + object. + + For example, provided each object of type `controller` needed a `router`. + one would do the following: + + ```javascript + var container = new Container(); + + container.register('router:main', Router); + container.register('controller:user', UserController); + container.register('controller:post', PostController); + + container.typeInjection('controller', 'router', 'router:main'); + + var user = container.lookup('controller:user'); + var post = container.lookup('controller:post'); + + user.router instanceof Router; //=> true + post.router instanceof Router; //=> true + + // both controllers share the same router + user.router === post.router; //=> true + ``` + + @method typeInjection + @param {String} type + @param {String} property + @param {String} fullName + */ + typeInjection: function(type, property, fullName) { + if (this.parent) { illegalChildOperation('typeInjection'); } + + addTypeInjection(this.typeInjections, type, property, fullName); + }, + + /** + Defines injection rules. + + These rules are used to inject dependencies onto objects when they + are instantiated. + + Two forms of injections are possible: + + * Injecting one fullName on another fullName + * Injecting one fullName on a type + + Example: + + ```javascript + var container = new Container(); + + container.register('source:main', Source); + container.register('model:user', User); + container.register('model:post', Post); + + // injecting one fullName on another fullName + // eg. each user model gets a post model + container.injection('model:user', 'post', 'model:post'); + + // injecting one fullName on another type + container.injection('model', 'source', 'source:main'); + + var user = container.lookup('model:user'); + var post = container.lookup('model:post'); + + user.source instanceof Source; //=> true + post.source instanceof Source; //=> true + + user.post instanceof Post; //=> true + + // and both models share the same source + user.source === post.source; //=> true + ``` + + @method injection + @param {String} factoryName + @param {String} property + @param {String} injectionName + */ + injection: function(factoryName, property, injectionName) { + if (this.parent) { illegalChildOperation('injection'); } + + if (factoryName.indexOf(':') === -1) { + return this.typeInjection(factoryName, property, injectionName); + } + + addInjection(this.injections, factoryName, property, injectionName); + }, + + + /** + @private + + Used only via `factoryInjection`. + + Provides a specialized form of injection, specifically enabling + all factory of one type to be injected with a reference to another + object. + + For example, provided each factory of type `model` needed a `store`. + one would do the following: + + ```javascript + var container = new Container(); + + container.registerFactory('model:user', User); + container.register('store:main', SomeStore); + + container.factoryTypeInjection('model', 'store', 'store:main'); + + var store = container.lookup('store:main'); + var UserFactory = container.lookupFactory('model:user'); + + UserFactory.store instanceof SomeStore; //=> true + ``` + + @method factoryTypeInjection + @param {String} type + @param {String} property + @param {String} fullName + */ + factoryTypeInjection: function(type, property, fullName) { + if (this.parent) { illegalChildOperation('factoryTypeInjection'); } + + addTypeInjection(this.factoryTypeInjections, type, property, fullName); + }, + + /** + Defines factory injection rules. + + Similar to regular injection rules, but are run against factories, via + `Container#lookupFactory`. + + These rules are used to inject objects onto factories when they + are looked up. + + Two forms of injections are possible: + + * Injecting one fullName on another fullName + * Injecting one fullName on a type + + Example: + + ```javascript + var container = new Container(); + + container.register('store:main', Store); + container.register('store:secondary', OtherStore); + container.register('model:user', User); + container.register('model:post', Post); + + // injecting one fullName on another type + container.factoryInjection('model', 'store', 'store:main'); + + // injecting one fullName on another fullName + container.factoryInjection('model:post', 'secondaryStore', 'store:secondary'); + + var UserFactory = container.lookupFactory('model:user'); + var PostFactory = container.lookupFactory('model:post'); + var store = container.lookup('store:main'); + + UserFactory.store instanceof Store; //=> true + UserFactory.secondaryStore instanceof OtherStore; //=> false + + PostFactory.store instanceof Store; //=> true + PostFactory.secondaryStore instanceof OtherStore; //=> true + + // and both models share the same source instance + UserFactory.store === PostFactory.store; //=> true + ``` + + @method factoryInjection + @param {String} factoryName + @param {String} property + @param {String} injectionName + */ + factoryInjection: function(factoryName, property, injectionName) { + if (this.parent) { illegalChildOperation('injection'); } + + if (factoryName.indexOf(':') === -1) { + return this.factoryTypeInjection(factoryName, property, injectionName); + } + + addInjection(this.factoryInjections, factoryName, property, injectionName); + }, + + /** + A depth first traversal, destroying the container, its descendant containers and all + their managed objects. + + @method destroy + */ + destroy: function() { + this.isDestroyed = true; + + for (var i=0, l=this.children.length; i w. +*/ +Ember.compare = function compare(v, w) { + if (v === w) { return 0; } + + var type1 = Ember.typeOf(v); + var type2 = Ember.typeOf(w); + + var Comparable = Ember.Comparable; + if (Comparable) { + if (type1==='instance' && Comparable.detect(v.constructor)) { + return v.constructor.compare(v, w); + } + + if (type2 === 'instance' && Comparable.detect(w.constructor)) { + return 1-w.constructor.compare(w, v); + } + } + + // If we haven't yet generated a reverse-mapping of Ember.ORDER_DEFINITION, + // do so now. + var mapping = Ember.ORDER_DEFINITION_MAPPING; + if (!mapping) { + var order = Ember.ORDER_DEFINITION; + mapping = Ember.ORDER_DEFINITION_MAPPING = {}; + var idx, len; + for (idx = 0, len = order.length; idx < len; ++idx) { + mapping[order[idx]] = idx; + } + + // We no longer need Ember.ORDER_DEFINITION. + delete Ember.ORDER_DEFINITION; + } + + var type1Index = mapping[type1]; + var type2Index = mapping[type2]; + + if (type1Index < type2Index) { return -1; } + if (type1Index > type2Index) { return 1; } + + // types are equal - so we have to check values now + switch (type1) { + case 'boolean': + case 'number': + if (v < w) { return -1; } + if (v > w) { return 1; } + return 0; + + case 'string': + var comp = v.localeCompare(w); + if (comp < 0) { return -1; } + if (comp > 0) { return 1; } + return 0; + + case 'array': + var vLen = v.length; + var wLen = w.length; + var l = Math.min(vLen, wLen); + var r = 0; + var i = 0; + while (r === 0 && i < l) { + r = compare(v[i],w[i]); + i++; + } + if (r !== 0) { return r; } + + // all elements are equal now + // shorter array should be ordered first + if (vLen < wLen) { return -1; } + if (vLen > wLen) { return 1; } + // arrays are equal now + return 0; + + case 'instance': + if (Ember.Comparable && Ember.Comparable.detect(v)) { + return v.compare(v, w); + } + return 0; + + case 'date': + var vNum = v.getTime(); + var wNum = w.getTime(); + if (vNum < wNum) { return -1; } + if (vNum > wNum) { return 1; } + return 0; + + default: + return 0; + } +}; + +function _copy(obj, deep, seen, copies) { + var ret, loc, key; + + // primitive data types are immutable, just return them. + if ('object' !== typeof obj || obj===null) return obj; + + // avoid cyclical loops + if (deep && (loc=indexOf(seen, obj))>=0) return copies[loc]; + + Ember.assert('Cannot clone an Ember.Object that does not implement Ember.Copyable', !(obj instanceof Ember.Object) || (Ember.Copyable && Ember.Copyable.detect(obj))); + + // IMPORTANT: this specific test will detect a native array only. Any other + // object will need to implement Copyable. + if (Ember.typeOf(obj) === 'array') { + ret = obj.slice(); + if (deep) { + loc = ret.length; + while(--loc>=0) ret[loc] = _copy(ret[loc], deep, seen, copies); + } + } else if (Ember.Copyable && Ember.Copyable.detect(obj)) { + ret = obj.copy(deep, seen, copies); + } else { + ret = {}; + for(key in obj) { + if (!obj.hasOwnProperty(key)) continue; + + // Prevents browsers that don't respect non-enumerability from + // copying internal Ember properties + if (key.substring(0,2) === '__') continue; + + ret[key] = deep ? _copy(obj[key], deep, seen, copies) : obj[key]; + } + } + + if (deep) { + seen.push(obj); + copies.push(ret); + } + + return ret; +} + +/** + Creates a clone of the passed object. This function can take just about + any type of object and create a clone of it, including primitive values + (which are not actually cloned because they are immutable). + + If the passed object implements the `clone()` method, then this function + will simply call that method and return the result. + + @method copy + @for Ember + @param {Object} obj The object to clone + @param {Boolean} deep If true, a deep copy of the object is made + @return {Object} The cloned object +*/ +Ember.copy = function(obj, deep) { + // fast paths + if ('object' !== typeof obj || obj===null) return obj; // can't copy primitives + if (Ember.Copyable && Ember.Copyable.detect(obj)) return obj.copy(deep); + return _copy(obj, deep, deep ? [] : null, deep ? [] : null); +}; + +/** + Convenience method to inspect an object. This method will attempt to + convert the object into a useful string description. + + It is a pretty simple implementation. If you want something more robust, + use something like JSDump: https://github.com/NV/jsDump + + @method inspect + @for Ember + @param {Object} obj The object you want to inspect. + @return {String} A description of the object +*/ +Ember.inspect = function(obj) { + var type = Ember.typeOf(obj); + if (type === 'array') { + return '[' + obj + ']'; + } + if (type !== 'object') { + return obj + ''; + } + + var v, ret = []; + for(var key in obj) { + if (obj.hasOwnProperty(key)) { + v = obj[key]; + if (v === 'toString') { continue; } // ignore useless items + if (Ember.typeOf(v) === 'function') { v = "function() { ... }"; } + ret.push(key + ": " + v); + } + } + return "{" + ret.join(", ") + "}"; +}; + +/** + Compares two objects, returning true if they are logically equal. This is + a deeper comparison than a simple triple equal. For sets it will compare the + internal objects. For any other object that implements `isEqual()` it will + respect that method. + + ```javascript + Ember.isEqual('hello', 'hello'); // true + Ember.isEqual(1, 2); // false + Ember.isEqual([4,2], [4,2]); // false + ``` + + @method isEqual + @for Ember + @param {Object} a first object to compare + @param {Object} b second object to compare + @return {Boolean} +*/ +Ember.isEqual = function(a, b) { + if (a && 'function'===typeof a.isEqual) return a.isEqual(b); + return a === b; +}; + +// Used by Ember.compare +Ember.ORDER_DEFINITION = Ember.ENV.ORDER_DEFINITION || [ + 'undefined', + 'null', + 'boolean', + 'number', + 'string', + 'array', + 'object', + 'instance', + 'function', + 'class', + 'date' +]; + +/** + Returns all of the keys defined on an object or hash. This is useful + when inspecting objects for debugging. On browsers that support it, this + uses the native `Object.keys` implementation. + + @method keys + @for Ember + @param {Object} obj + @return {Array} Array containing keys of obj +*/ +Ember.keys = Object.keys; + +if (!Ember.keys || Ember.create.isSimulated) { + var prototypeProperties = [ + 'constructor', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'valueOf', + 'toLocaleString', + 'toString' + ], + pushPropertyName = function(obj, array, key) { + // Prevents browsers that don't respect non-enumerability from + // copying internal Ember properties + if (key.substring(0,2) === '__') return; + if (key === '_super') return; + if (indexOf(array, key) >= 0) return; + if (!obj.hasOwnProperty(key)) return; + + array.push(key); + }; + + Ember.keys = function(obj) { + var ret = [], key; + for (key in obj) { + pushPropertyName(obj, ret, key); + } + + // IE8 doesn't enumerate property that named the same as prototype properties. + for (var i = 0, l = prototypeProperties.length; i < l; i++) { + key = prototypeProperties[i]; + + pushPropertyName(obj, ret, key); + } + + return ret; + }; +} + +})(); + + + +(function() { +/** +@module ember +@submodule ember-runtime +*/ + +var STRING_DASHERIZE_REGEXP = (/[ _]/g); +var STRING_DASHERIZE_CACHE = {}; +var STRING_DECAMELIZE_REGEXP = (/([a-z\d])([A-Z])/g); +var STRING_CAMELIZE_REGEXP = (/(\-|_|\.|\s)+(.)?/g); +var STRING_UNDERSCORE_REGEXP_1 = (/([a-z\d])([A-Z]+)/g); +var STRING_UNDERSCORE_REGEXP_2 = (/\-|\s+/g); + +/** + Defines the hash of localized strings for the current language. Used by + the `Ember.String.loc()` helper. To localize, add string values to this + hash. + + @property STRINGS + @for Ember + @type Hash +*/ +Ember.STRINGS = {}; + +/** + Defines string helper methods including string formatting and localization. + Unless `Ember.EXTEND_PROTOTYPES.String` is `false` these methods will also be + added to the `String.prototype` as well. + + @class String + @namespace Ember + @static +*/ +Ember.String = { + + /** + Apply formatting options to the string. This will look for occurrences + of "%@" in your string and substitute them with the arguments you pass into + this method. If you want to control the specific order of replacement, + you can add a number after the key as well to indicate which argument + you want to insert. + + Ordered insertions are most useful when building loc strings where values + you need to insert may appear in different orders. + + ```javascript + "Hello %@ %@".fmt('John', 'Doe'); // "Hello John Doe" + "Hello %@2, %@1".fmt('John', 'Doe'); // "Hello Doe, John" + ``` + + @method fmt + @param {String} str The string to format + @param {Array} formats An array of parameters to interpolate into string. + @return {String} formatted string + */ + fmt: function(str, formats) { + // first, replace any ORDERED replacements. + var idx = 0; // the current index for non-numerical replacements + return str.replace(/%@([0-9]+)?/g, function(s, argIndex) { + argIndex = (argIndex) ? parseInt(argIndex, 10) - 1 : idx++; + s = formats[argIndex]; + return (s === null) ? '(null)' : (s === undefined) ? '' : Ember.inspect(s); + }) ; + }, + + /** + Formats the passed string, but first looks up the string in the localized + strings hash. This is a convenient way to localize text. See + `Ember.String.fmt()` for more information on formatting. + + Note that it is traditional but not required to prefix localized string + keys with an underscore or other character so you can easily identify + localized strings. + + ```javascript + Ember.STRINGS = { + '_Hello World': 'Bonjour le monde', + '_Hello %@ %@': 'Bonjour %@ %@' + }; + + Ember.String.loc("_Hello World"); // 'Bonjour le monde'; + Ember.String.loc("_Hello %@ %@", ["John", "Smith"]); // "Bonjour John Smith"; + ``` + + @method loc + @param {String} str The string to format + @param {Array} formats Optional array of parameters to interpolate into string. + @return {String} formatted string + */ + loc: function(str, formats) { + str = Ember.STRINGS[str] || str; + return Ember.String.fmt(str, formats) ; + }, + + /** + Splits a string into separate units separated by spaces, eliminating any + empty strings in the process. This is a convenience method for split that + is mostly useful when applied to the `String.prototype`. + + ```javascript + Ember.String.w("alpha beta gamma").forEach(function(key) { + console.log(key); + }); + + // > alpha + // > beta + // > gamma + ``` + + @method w + @param {String} str The string to split + @return {String} split string + */ + w: function(str) { return str.split(/\s+/); }, + + /** + Converts a camelized string into all lower case separated by underscores. + + ```javascript + 'innerHTML'.decamelize(); // 'inner_html' + 'action_name'.decamelize(); // 'action_name' + 'css-class-name'.decamelize(); // 'css-class-name' + 'my favorite items'.decamelize(); // 'my favorite items' + ``` + + @method decamelize + @param {String} str The string to decamelize. + @return {String} the decamelized string. + */ + decamelize: function(str) { + return str.replace(STRING_DECAMELIZE_REGEXP, '$1_$2').toLowerCase(); + }, + + /** + Replaces underscores, spaces, or camelCase with dashes. + + ```javascript + 'innerHTML'.dasherize(); // 'inner-html' + 'action_name'.dasherize(); // 'action-name' + 'css-class-name'.dasherize(); // 'css-class-name' + 'my favorite items'.dasherize(); // 'my-favorite-items' + ``` + + @method dasherize + @param {String} str The string to dasherize. + @return {String} the dasherized string. + */ + dasherize: function(str) { + var cache = STRING_DASHERIZE_CACHE, + hit = cache.hasOwnProperty(str), + ret; + + if (hit) { + return cache[str]; + } else { + ret = Ember.String.decamelize(str).replace(STRING_DASHERIZE_REGEXP,'-'); + cache[str] = ret; + } + + return ret; + }, + + /** + Returns the lowerCamelCase form of a string. + + ```javascript + 'innerHTML'.camelize(); // 'innerHTML' + 'action_name'.camelize(); // 'actionName' + 'css-class-name'.camelize(); // 'cssClassName' + 'my favorite items'.camelize(); // 'myFavoriteItems' + 'My Favorite Items'.camelize(); // 'myFavoriteItems' + ``` + + @method camelize + @param {String} str The string to camelize. + @return {String} the camelized string. + */ + camelize: function(str) { + return str.replace(STRING_CAMELIZE_REGEXP, function(match, separator, chr) { + return chr ? chr.toUpperCase() : ''; + }).replace(/^([A-Z])/, function(match, separator, chr) { + return match.toLowerCase(); + }); + }, + + /** + Returns the UpperCamelCase form of a string. + + ```javascript + 'innerHTML'.classify(); // 'InnerHTML' + 'action_name'.classify(); // 'ActionName' + 'css-class-name'.classify(); // 'CssClassName' + 'my favorite items'.classify(); // 'MyFavoriteItems' + ``` + + @method classify + @param {String} str the string to classify + @return {String} the classified string + */ + classify: function(str) { + var parts = str.split("."), + out = []; + + for (var i=0, l=parts.length; i= 0) { + var baseValue = this[keyName]; + + if (baseValue) { + if ('function' === typeof baseValue.concat) { + value = baseValue.concat(value); + } else { + value = Ember.makeArray(baseValue).concat(value); + } + } else { + value = Ember.makeArray(value); + } + } + + if (desc) { + desc.set(this, keyName, value); + } else { + if (typeof this.setUnknownProperty === 'function' && !(keyName in this)) { + this.setUnknownProperty(keyName, value); + } else if (MANDATORY_SETTER) { + Ember.defineProperty(this, keyName, null, value); // setup mandatory setter + } else { + this[keyName] = value; + } + } + } + } + } + finishPartial(this, m); + this.init.apply(this, arguments); + m.proto = proto; + finishChains(this); + sendEvent(this, "init"); + }; + + Class.toString = Mixin.prototype.toString; + Class.willReopen = function() { + if (wasApplied) { + Class.PrototypeMixin = Mixin.create(Class.PrototypeMixin); + } + + wasApplied = false; + }; + Class._initMixins = function(args) { initMixins = args; }; + Class._initProperties = function(args) { initProperties = args; }; + + Class.proto = function() { + var superclass = Class.superclass; + if (superclass) { superclass.proto(); } + + if (!wasApplied) { + wasApplied = true; + Class.PrototypeMixin.applyPartial(Class.prototype); + rewatch(Class.prototype); + } + + return this.prototype; + }; + + return Class; + +} + +/** + @class CoreObject + @namespace Ember +*/ +var CoreObject = makeCtor(); +CoreObject.toString = function() { return "Ember.CoreObject"; }; + +CoreObject.PrototypeMixin = Mixin.create({ + reopen: function() { + applyMixin(this, arguments, true); + return this; + }, + + /** + An overridable method called when objects are instantiated. By default, + does nothing unless it is overridden during class definition. + + Example: + + ```javascript + App.Person = Ember.Object.extend({ + init: function() { + alert('Name is ' + this.get('name')); + } + }); + + var steve = App.Person.create({ + name: "Steve" + }); + + // alerts 'Name is Steve'. + ``` + + NOTE: If you do override `init` for a framework class like `Ember.View` or + `Ember.ArrayController`, be sure to call `this._super()` in your + `init` declaration! If you don't, Ember may not have an opportunity to + do important setup work, and you'll see strange behavior in your + application. + + @method init + */ + init: function() {}, + + /** + Defines the properties that will be concatenated from the superclass + (instead of overridden). + + By default, when you extend an Ember class a property defined in + the subclass overrides a property with the same name that is defined + in the superclass. However, there are some cases where it is preferable + to build up a property's value by combining the superclass' property + value with the subclass' value. An example of this in use within Ember + is the `classNames` property of `Ember.View`. + + Here is some sample code showing the difference between a concatenated + property and a normal one: + + ```javascript + App.BarView = Ember.View.extend({ + someNonConcatenatedProperty: ['bar'], + classNames: ['bar'] + }); + + App.FooBarView = App.BarView.extend({ + someNonConcatenatedProperty: ['foo'], + classNames: ['foo'], + }); + + var fooBarView = App.FooBarView.create(); + fooBarView.get('someNonConcatenatedProperty'); // ['foo'] + fooBarView.get('classNames'); // ['ember-view', 'bar', 'foo'] + ``` + + This behavior extends to object creation as well. Continuing the + above example: + + ```javascript + var view = App.FooBarView.create({ + someNonConcatenatedProperty: ['baz'], + classNames: ['baz'] + }) + view.get('someNonConcatenatedProperty'); // ['baz'] + view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz'] + ``` + Adding a single property that is not an array will just add it in the array: + + ```javascript + var view = App.FooBarView.create({ + classNames: 'baz' + }) + view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz'] + ``` + + Using the `concatenatedProperties` property, we can tell to Ember that mix + the content of the properties. + + In `Ember.View` the `classNameBindings` and `attributeBindings` properties + are also concatenated, in addition to `classNames`. + + This feature is available for you to use throughout the Ember object model, + although typical app developers are likely to use it infrequently. Since + it changes expectations about behavior of properties, you should properly + document its usage in each individual concatenated property (to not + mislead your users to think they can override the property in a subclass). + + @property concatenatedProperties + @type Array + @default null + */ + concatenatedProperties: null, + + /** + Destroyed object property flag. + + if this property is `true` the observers and bindings were already + removed by the effect of calling the `destroy()` method. + + @property isDestroyed + @default false + */ + isDestroyed: false, + + /** + Destruction scheduled flag. The `destroy()` method has been called. + + The object stays intact until the end of the run loop at which point + the `isDestroyed` flag is set. + + @property isDestroying + @default false + */ + isDestroying: false, + + /** + Destroys an object by setting the `isDestroyed` flag and removing its + metadata, which effectively destroys observers and bindings. + + If you try to set a property on a destroyed object, an exception will be + raised. + + Note that destruction is scheduled for the end of the run loop and does not + happen immediately. It will set an isDestroying flag immediately. + + @method destroy + @return {Ember.Object} receiver + */ + destroy: function() { + if (this.isDestroying) { return; } + this.isDestroying = true; + + schedule('actions', this, this.willDestroy); + schedule('destroy', this, this._scheduledDestroy); + return this; + }, + + /** + Override to implement teardown. + + @method willDestroy + */ + willDestroy: Ember.K, + + /** + @private + + Invoked by the run loop to actually destroy the object. This is + scheduled for execution by the `destroy` method. + + @method _scheduledDestroy + */ + _scheduledDestroy: function() { + if (this.isDestroyed) { return; } + destroy(this); + this.isDestroyed = true; + }, + + bind: function(to, from) { + if (!(from instanceof Ember.Binding)) { from = Ember.Binding.from(from); } + from.to(to).connect(this); + return from; + }, + + /** + Returns a string representation which attempts to provide more information + than Javascript's `toString` typically does, in a generic way for all Ember + objects. + + App.Person = Em.Object.extend() + person = App.Person.create() + person.toString() //=> "" + + If the object's class is not defined on an Ember namespace, it will + indicate it is a subclass of the registered superclass: + + Student = App.Person.extend() + student = Student.create() + student.toString() //=> "<(subclass of App.Person):ember1025>" + + If the method `toStringExtension` is defined, its return value will be + included in the output. + + App.Teacher = App.Person.extend({ + toStringExtension: function() { + return this.get('fullName'); + } + }); + teacher = App.Teacher.create() + teacher.toString(); //=> "" + + @method toString + @return {String} string representation + */ + toString: function toString() { + var hasToStringExtension = typeof this.toStringExtension === 'function', + extension = hasToStringExtension ? ":" + this.toStringExtension() : ''; + var ret = '<'+this.constructor.toString()+':'+guidFor(this)+extension+'>'; + this.toString = makeToString(ret); + return ret; + } +}); + +CoreObject.PrototypeMixin.ownerConstructor = CoreObject; + +function makeToString(ret) { + return function() { return ret; }; +} + +if (Ember.config.overridePrototypeMixin) { + Ember.config.overridePrototypeMixin(CoreObject.PrototypeMixin); +} + +CoreObject.__super__ = null; + +var ClassMixin = Mixin.create({ + + ClassMixin: Ember.required(), + + PrototypeMixin: Ember.required(), + + isClass: true, + + isMethod: false, + + /** + Creates a new subclass. + + ```javascript + App.Person = Ember.Object.extend({ + say: function(thing) { + alert(thing); + } + }); + ``` + + This defines a new subclass of Ember.Object: `App.Person`. It contains one method: `say()`. + + You can also create a subclass from any existing class by calling its `extend()` method. For example, you might want to create a subclass of Ember's built-in `Ember.View` class: + + ```javascript + App.PersonView = Ember.View.extend({ + tagName: 'li', + classNameBindings: ['isAdministrator'] + }); + ``` + + When defining a subclass, you can override methods but still access the implementation of your parent class by calling the special `_super()` method: + + ```javascript + App.Person = Ember.Object.extend({ + say: function(thing) { + var name = this.get('name'); + alert(name + ' says: ' + thing); + } + }); + + App.Soldier = App.Person.extend({ + say: function(thing) { + this._super(thing + ", sir!"); + }, + march: function(numberOfHours) { + alert(this.get('name') + ' marches for ' + numberOfHours + ' hours.') + } + }); + + var yehuda = App.Soldier.create({ + name: "Yehuda Katz" + }); + + yehuda.say("Yes"); // alerts "Yehuda Katz says: Yes, sir!" + ``` + + The `create()` on line #17 creates an *instance* of the `App.Soldier` class. The `extend()` on line #8 creates a *subclass* of `App.Person`. Any instance of the `App.Person` class will *not* have the `march()` method. + + You can also pass `Ember.Mixin` classes to add additional properties to the subclass. + + ```javascript + App.Person = Ember.Object.extend({ + say: function(thing) { + alert(this.get('name') + ' says: ' + thing); + } + }); + + App.SingingMixin = Ember.Mixin.create({ + sing: function(thing){ + alert(this.get('name') + ' sings: la la la ' + thing); + } + }); + + App.BroadwayStar = App.Person.extend(App.SingingMixin, { + dance: function() { + alert(this.get('name') + ' dances: tap tap tap tap '); + } + }); + ``` + + The `App.BroadwayStar` class contains three methods: `say()`, `sing()`, and `dance()`. + + @method extend + @static + + @param {Ember.Mixin} [mixins]* One or more Ember.Mixin classes + @param {Object} [arguments]* Object containing values to use within the new class + */ + extend: function() { + var Class = makeCtor(), proto; + Class.ClassMixin = Mixin.create(this.ClassMixin); + Class.PrototypeMixin = Mixin.create(this.PrototypeMixin); + + Class.ClassMixin.ownerConstructor = Class; + Class.PrototypeMixin.ownerConstructor = Class; + + reopen.apply(Class.PrototypeMixin, arguments); + + Class.superclass = this; + Class.__super__ = this.prototype; + + proto = Class.prototype = o_create(this.prototype); + proto.constructor = Class; + generateGuid(proto); + meta(proto).proto = proto; // this will disable observers on prototype + + Class.ClassMixin.apply(Class); + return Class; + }, + + /** + Equivalent to doing `extend(arguments).create()`. + If possible use the normal `create` method instead. + + @method createWithMixins + @static + @param [arguments]* + */ + createWithMixins: function() { + var C = this; + if (arguments.length>0) { this._initMixins(arguments); } + return new C(); + }, + + /** + Creates an instance of a class. Accepts either no arguments, or an object + containing values to initialize the newly instantiated object with. + + ```javascript + App.Person = Ember.Object.extend({ + helloWorld: function() { + alert("Hi, my name is " + this.get('name')); + } + }); + + var tom = App.Person.create({ + name: 'Tom Dale' + }); + + tom.helloWorld(); // alerts "Hi, my name is Tom Dale". + ``` + + `create` will call the `init` function if defined during + `Ember.AnyObject.extend` + + If no arguments are passed to `create`, it will not set values to the new + instance during initialization: + + ```javascript + var noName = App.Person.create(); + noName.helloWorld(); // alerts undefined + ``` + + NOTE: For performance reasons, you cannot declare methods or computed + properties during `create`. You should instead declare methods and computed + properties when using `extend` or use the `createWithMixins` shorthand. + + @method create + @static + @param [arguments]* + */ + create: function() { + var C = this; + if (arguments.length>0) { this._initProperties(arguments); } + return new C(); + }, + + /** + + Augments a constructor's prototype with additional + properties and functions: + + ```javascript + MyObject = Ember.Object.extend({ + name: 'an object' + }); + + o = MyObject.create(); + o.get('name'); // 'an object' + + MyObject.reopen({ + say: function(msg){ + console.log(msg); + } + }) + + o2 = MyObject.create(); + o2.say("hello"); // logs "hello" + + o.say("goodbye"); // logs "goodbye" + ``` + + To add functions and properties to the constructor itself, + see `reopenClass` + + @method reopen + */ + reopen: function() { + this.willReopen(); + reopen.apply(this.PrototypeMixin, arguments); + return this; + }, + + /** + Augments a constructor's own properties and functions: + + ```javascript + MyObject = Ember.Object.extend({ + name: 'an object' + }); + + + MyObject.reopenClass({ + canBuild: false + }); + + MyObject.canBuild; // false + o = MyObject.create(); + ``` + + In other words, this creates static properties and functions for the class. These are only available on the class + and not on any instance of that class. + + ```javascript + App.Person = Ember.Object.extend({ + name : "", + sayHello : function(){ + alert("Hello. My name is " + this.get('name')); + } + }); + + App.Person.reopenClass({ + species : "Homo sapiens", + createPerson: function(newPersonsName){ + return App.Person.create({ + name:newPersonsName + }); + } + }); + + var tom = App.Person.create({ + name : "Tom Dale" + }); + var yehuda = App.Person.createPerson("Yehuda Katz"); + + tom.sayHello(); // "Hello. My name is Tom Dale" + yehuda.sayHello(); // "Hello. My name is Yehuda Katz" + alert(App.Person.species); // "Homo sapiens" + ``` + + Note that `species` and `createPerson` are *not* valid on the `tom` and `yehuda` + variables. They are only valid on `App.Person`. + + To add functions and properties to instances of + a constructor by extending the constructor's prototype + see `reopen` + + @method reopenClass + */ + reopenClass: function() { + reopen.apply(this.ClassMixin, arguments); + applyMixin(this, arguments, false); + return this; + }, + + detect: function(obj) { + if ('function' !== typeof obj) { return false; } + while(obj) { + if (obj===this) { return true; } + obj = obj.superclass; + } + return false; + }, + + detectInstance: function(obj) { + return obj instanceof this; + }, + + /** + In some cases, you may want to annotate computed properties with additional + metadata about how they function or what values they operate on. For + example, computed property functions may close over variables that are then + no longer available for introspection. + + You can pass a hash of these values to a computed property like this: + + ```javascript + person: function() { + var personId = this.get('personId'); + return App.Person.create({ id: personId }); + }.property().meta({ type: App.Person }) + ``` + + Once you've done this, you can retrieve the values saved to the computed + property from your class like this: + + ```javascript + MyClass.metaForProperty('person'); + ``` + + This will return the original hash that was passed to `meta()`. + + @method metaForProperty + @param key {String} property name + */ + metaForProperty: function(key) { + var desc = meta(this.proto(), false).descs[key]; + + Ember.assert("metaForProperty() could not find a computed property with key '"+key+"'.", !!desc && desc instanceof Ember.ComputedProperty); + return desc._meta || {}; + }, + + /** + Iterate over each computed property for the class, passing its name + and any associated metadata (see `metaForProperty`) to the callback. + + @method eachComputedProperty + @param {Function} callback + @param {Object} binding + */ + eachComputedProperty: function(callback, binding) { + var proto = this.proto(), + descs = meta(proto).descs, + empty = {}, + property; + + for (var name in descs) { + property = descs[name]; + + if (property instanceof Ember.ComputedProperty) { + callback.call(binding || this, name, property._meta || empty); + } + } + } + +}); + +ClassMixin.ownerConstructor = CoreObject; + +if (Ember.config.overrideClassMixin) { + Ember.config.overrideClassMixin(ClassMixin); +} + +CoreObject.ClassMixin = ClassMixin; +ClassMixin.apply(CoreObject); + +Ember.CoreObject = CoreObject; + +})(); + + + +(function() { +/** +@module ember +@submodule ember-runtime +*/ + +/** + `Ember.Object` is the main base class for all Ember objects. It is a subclass + of `Ember.CoreObject` with the `Ember.Observable` mixin applied. For details, + see the documentation for each of these. + + @class Object + @namespace Ember + @extends Ember.CoreObject + @uses Ember.Observable +*/ +Ember.Object = Ember.CoreObject.extend(Ember.Observable); +Ember.Object.toString = function() { return "Ember.Object"; }; + +})(); + + + +(function() { +/** +@module ember +@submodule ember-runtime +*/ + +var get = Ember.get, indexOf = Ember.ArrayPolyfills.indexOf; + +/** + A Namespace is an object usually used to contain other objects or methods + such as an application or framework. Create a namespace anytime you want + to define one of these new containers. + + # Example Usage + + ```javascript + MyFramework = Ember.Namespace.create({ + VERSION: '1.0.0' + }); + ``` + + @class Namespace + @namespace Ember + @extends Ember.Object +*/ +var Namespace = Ember.Namespace = Ember.Object.extend({ + isNamespace: true, + + init: function() { + Ember.Namespace.NAMESPACES.push(this); + Ember.Namespace.PROCESSED = false; + }, + + toString: function() { + var name = get(this, 'name'); + if (name) { return name; } + + findNamespaces(); + return this[Ember.GUID_KEY+'_name']; + }, + + nameClasses: function() { + processNamespace([this.toString()], this, {}); + }, + + destroy: function() { + var namespaces = Ember.Namespace.NAMESPACES; + Ember.lookup[this.toString()] = undefined; + namespaces.splice(indexOf.call(namespaces, this), 1); + this._super(); + } +}); + +Namespace.reopenClass({ + NAMESPACES: [Ember], + NAMESPACES_BY_ID: {}, + PROCESSED: false, + processAll: processAllNamespaces, + byName: function(name) { + if (!Ember.BOOTED) { + processAllNamespaces(); + } + + return NAMESPACES_BY_ID[name]; + } +}); + +var NAMESPACES_BY_ID = Namespace.NAMESPACES_BY_ID; + +var hasOwnProp = ({}).hasOwnProperty, + guidFor = Ember.guidFor; + +function processNamespace(paths, root, seen) { + var idx = paths.length; + + NAMESPACES_BY_ID[paths.join('.')] = root; + + // Loop over all of the keys in the namespace, looking for classes + for(var key in root) { + if (!hasOwnProp.call(root, key)) { continue; } + var obj = root[key]; + + // If we are processing the `Ember` namespace, for example, the + // `paths` will start with `["Ember"]`. Every iteration through + // the loop will update the **second** element of this list with + // the key, so processing `Ember.View` will make the Array + // `['Ember', 'View']`. + paths[idx] = key; + + // If we have found an unprocessed class + if (obj && obj.toString === classToString) { + // Replace the class' `toString` with the dot-separated path + // and set its `NAME_KEY` + obj.toString = makeToString(paths.join('.')); + obj[NAME_KEY] = paths.join('.'); + + // Support nested namespaces + } else if (obj && obj.isNamespace) { + // Skip aliased namespaces + if (seen[guidFor(obj)]) { continue; } + seen[guidFor(obj)] = true; + + // Process the child namespace + processNamespace(paths, obj, seen); + } + } + + paths.length = idx; // cut out last item +} + +function findNamespaces() { + var Namespace = Ember.Namespace, lookup = Ember.lookup, obj, isNamespace; + + if (Namespace.PROCESSED) { return; } + + for (var prop in lookup) { + // These don't raise exceptions but can cause warnings + if (prop === "parent" || prop === "top" || prop === "frameElement" || prop === "webkitStorageInfo") { continue; } + + // get(window.globalStorage, 'isNamespace') would try to read the storage for domain isNamespace and cause exception in Firefox. + // globalStorage is a storage obsoleted by the WhatWG storage specification. See https://developer.mozilla.org/en/DOM/Storage#globalStorage + if (prop === "globalStorage" && lookup.StorageList && lookup.globalStorage instanceof lookup.StorageList) { continue; } + // Unfortunately, some versions of IE don't support window.hasOwnProperty + if (lookup.hasOwnProperty && !lookup.hasOwnProperty(prop)) { continue; } + + // At times we are not allowed to access certain properties for security reasons. + // There are also times where even if we can access them, we are not allowed to access their properties. + try { + obj = Ember.lookup[prop]; + isNamespace = obj && obj.isNamespace; + } catch (e) { + continue; + } + + if (isNamespace) { + Ember.deprecate("Namespaces should not begin with lowercase.", /^[A-Z]/.test(prop)); + obj[NAME_KEY] = prop; + } + } +} + +var NAME_KEY = Ember.NAME_KEY = Ember.GUID_KEY + '_name'; + +function superClassString(mixin) { + var superclass = mixin.superclass; + if (superclass) { + if (superclass[NAME_KEY]) { return superclass[NAME_KEY]; } + else { return superClassString(superclass); } + } else { + return; + } +} + +function classToString() { + if (!Ember.BOOTED && !this[NAME_KEY]) { + processAllNamespaces(); + } + + var ret; + + if (this[NAME_KEY]) { + ret = this[NAME_KEY]; + } else if (this._toString) { + ret = this._toString; + } else { + var str = superClassString(this); + if (str) { + ret = "(subclass of " + str + ")"; + } else { + ret = "(unknown mixin)"; + } + this.toString = makeToString(ret); + } + + return ret; +} + +function processAllNamespaces() { + var unprocessedNamespaces = !Namespace.PROCESSED, + unprocessedMixins = Ember.anyUnprocessedMixins; + + if (unprocessedNamespaces) { + findNamespaces(); + Namespace.PROCESSED = true; + } + + if (unprocessedNamespaces || unprocessedMixins) { + var namespaces = Namespace.NAMESPACES, namespace; + for (var i=0, l=namespaces.length; i1) args = a_slice.call(arguments, 1); + + this.forEach(function(x, idx) { + var method = x && x[methodName]; + if ('function' === typeof method) { + ret[idx] = args ? method.apply(x, args) : method.call(x); + } + }, this); + + return ret; + }, + + /** + Simply converts the enumerable into a genuine array. The order is not + guaranteed. Corresponds to the method implemented by Prototype. + + @method toArray + @return {Array} the enumerable as an array. + */ + toArray: function() { + var ret = Ember.A(); + this.forEach(function(o, idx) { ret[idx] = o; }); + return ret ; + }, + + /** + Returns a copy of the array with all null and undefined elements removed. + + ```javascript + var arr = ["a", null, "c", undefined]; + arr.compact(); // ["a", "c"] + ``` + + @method compact + @return {Array} the array without null and undefined elements. + */ + compact: function() { + return this.filter(function(value) { return value != null; }); + }, + + /** + Returns a new enumerable that excludes the passed value. The default + implementation returns an array regardless of the receiver type unless + the receiver does not contain the value. + + ```javascript + var arr = ["a", "b", "a", "c"]; + arr.without("a"); // ["b", "c"] + ``` + + @method without + @param {Object} value + @return {Ember.Enumerable} + */ + without: function(value) { + if (!this.contains(value)) return this; // nothing to do + var ret = Ember.A(); + this.forEach(function(k) { + if (k !== value) ret[ret.length] = k; + }) ; + return ret ; + }, + + /** + Returns a new enumerable that contains only unique values. The default + implementation returns an array regardless of the receiver type. + + ```javascript + var arr = ["a", "a", "b", "b"]; + arr.uniq(); // ["a", "b"] + ``` + + @method uniq + @return {Ember.Enumerable} + */ + uniq: function() { + var ret = Ember.A(); + this.forEach(function(k) { + if (a_indexOf(ret, k)<0) ret.push(k); + }); + return ret; + }, + + /** + This property will trigger anytime the enumerable's content changes. + You can observe this property to be notified of changes to the enumerables + content. + + For plain enumerables, this property is read only. `Ember.Array` overrides + this method. + + @property [] + @type Ember.Array + @return this + */ + '[]': Ember.computed(function(key, value) { + return this; + }), + + // .......................................................... + // ENUMERABLE OBSERVERS + // + + /** + Registers an enumerable observer. Must implement `Ember.EnumerableObserver` + mixin. + + @method addEnumerableObserver + @param {Object} target + @param {Hash} [opts] + @return this + */ + addEnumerableObserver: function(target, opts) { + var willChange = (opts && opts.willChange) || 'enumerableWillChange', + didChange = (opts && opts.didChange) || 'enumerableDidChange'; + + var hasObservers = get(this, 'hasEnumerableObservers'); + if (!hasObservers) Ember.propertyWillChange(this, 'hasEnumerableObservers'); + Ember.addListener(this, '@enumerable:before', target, willChange); + Ember.addListener(this, '@enumerable:change', target, didChange); + if (!hasObservers) Ember.propertyDidChange(this, 'hasEnumerableObservers'); + return this; + }, + + /** + Removes a registered enumerable observer. + + @method removeEnumerableObserver + @param {Object} target + @param {Hash} [opts] + @return this + */ + removeEnumerableObserver: function(target, opts) { + var willChange = (opts && opts.willChange) || 'enumerableWillChange', + didChange = (opts && opts.didChange) || 'enumerableDidChange'; + + var hasObservers = get(this, 'hasEnumerableObservers'); + if (hasObservers) Ember.propertyWillChange(this, 'hasEnumerableObservers'); + Ember.removeListener(this, '@enumerable:before', target, willChange); + Ember.removeListener(this, '@enumerable:change', target, didChange); + if (hasObservers) Ember.propertyDidChange(this, 'hasEnumerableObservers'); + return this; + }, + + /** + Becomes true whenever the array currently has observers watching changes + on the array. + + @property hasEnumerableObservers + @type Boolean + */ + hasEnumerableObservers: Ember.computed(function() { + return Ember.hasListeners(this, '@enumerable:change') || Ember.hasListeners(this, '@enumerable:before'); + }), + + + /** + Invoke this method just before the contents of your enumerable will + change. You can either omit the parameters completely or pass the objects + to be removed or added if available or just a count. + + @method enumerableContentWillChange + @param {Ember.Enumerable|Number} removing An enumerable of the objects to + be removed or the number of items to be removed. + @param {Ember.Enumerable|Number} adding An enumerable of the objects to be + added or the number of items to be added. + @chainable + */ + enumerableContentWillChange: function(removing, adding) { + + var removeCnt, addCnt, hasDelta; + + if ('number' === typeof removing) removeCnt = removing; + else if (removing) removeCnt = get(removing, 'length'); + else removeCnt = removing = -1; + + if ('number' === typeof adding) addCnt = adding; + else if (adding) addCnt = get(adding,'length'); + else addCnt = adding = -1; + + hasDelta = addCnt<0 || removeCnt<0 || addCnt-removeCnt!==0; + + if (removing === -1) removing = null; + if (adding === -1) adding = null; + + Ember.propertyWillChange(this, '[]'); + if (hasDelta) Ember.propertyWillChange(this, 'length'); + Ember.sendEvent(this, '@enumerable:before', [this, removing, adding]); + + return this; + }, + + /** + Invoke this method when the contents of your enumerable has changed. + This will notify any observers watching for content changes. If your are + implementing an ordered enumerable (such as an array), also pass the + start and end values where the content changed so that it can be used to + notify range observers. + + @method enumerableContentDidChange + @param {Number} [start] optional start offset for the content change. + For unordered enumerables, you should always pass -1. + @param {Ember.Enumerable|Number} removing An enumerable of the objects to + be removed or the number of items to be removed. + @param {Ember.Enumerable|Number} adding An enumerable of the objects to + be added or the number of items to be added. + @chainable + */ + enumerableContentDidChange: function(removing, adding) { + var removeCnt, addCnt, hasDelta; + + if ('number' === typeof removing) removeCnt = removing; + else if (removing) removeCnt = get(removing, 'length'); + else removeCnt = removing = -1; + + if ('number' === typeof adding) addCnt = adding; + else if (adding) addCnt = get(adding, 'length'); + else addCnt = adding = -1; + + hasDelta = addCnt<0 || removeCnt<0 || addCnt-removeCnt!==0; + + if (removing === -1) removing = null; + if (adding === -1) adding = null; + + Ember.sendEvent(this, '@enumerable:change', [this, removing, adding]); + if (hasDelta) Ember.propertyDidChange(this, 'length'); + Ember.propertyDidChange(this, '[]'); + + return this ; + } + +}); + + + Ember.Enumerable.reopen({ + /** + Converts the enumerable into an array and sorts by the keys + specified in the argument. + + You may provide multiple arguments to sort by multiple properties. + + @method sortBy + @param {String} property name(s) to sort on + @return {Array} The sorted array. + */ + sortBy: function() { + var sortKeys = arguments; + return this.toArray().sort(function(a, b){ + for(var i = 0; i < sortKeys.length; i++) { + var key = sortKeys[i], + propA = get(a, key), + propB = get(b, key); + // return 1 or -1 else continue to the next sortKey + var compareValue = Ember.compare(propA, propB); + if (compareValue) { return compareValue; } + } + return 0; + }); + } + }); + + +})(); + + + +(function() { +/** +@module ember +@submodule ember-runtime +*/ + +// .......................................................... +// HELPERS +// + +var get = Ember.get, set = Ember.set, isNone = Ember.isNone, map = Ember.EnumerableUtils.map, cacheFor = Ember.cacheFor; + +// .......................................................... +// ARRAY +// +/** + This module implements Observer-friendly Array-like behavior. This mixin is + picked up by the Array class as well as other controllers, etc. that want to + appear to be arrays. + + Unlike `Ember.Enumerable,` this mixin defines methods specifically for + collections that provide index-ordered access to their contents. When you + are designing code that needs to accept any kind of Array-like object, you + should use these methods instead of Array primitives because these will + properly notify observers of changes to the array. + + Although these methods are efficient, they do add a layer of indirection to + your application so it is a good idea to use them only when you need the + flexibility of using both true JavaScript arrays and "virtual" arrays such + as controllers and collections. + + You can use the methods defined in this module to access and modify array + contents in a KVO-friendly way. You can also be notified whenever the + membership of an array changes by changing the syntax of the property to + `.observes('*myProperty.[]')`. + + To support `Ember.Array` in your own class, you must override two + primitives to use it: `replace()` and `objectAt()`. + + Note that the Ember.Array mixin also incorporates the `Ember.Enumerable` + mixin. All `Ember.Array`-like objects are also enumerable. + + @class Array + @namespace Ember + @uses Ember.Enumerable + @since Ember 0.9.0 +*/ +Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.prototype */ { + + /** + Your array must support the `length` property. Your replace methods should + set this property whenever it changes. + + @property {Number} length + */ + length: Ember.required(), + + /** + Returns the object at the given `index`. If the given `index` is negative + or is greater or equal than the array length, returns `undefined`. + + This is one of the primitives you must implement to support `Ember.Array`. + If your object supports retrieving the value of an array item using `get()` + (i.e. `myArray.get(0)`), then you do not need to implement this method + yourself. + + ```javascript + var arr = ['a', 'b', 'c', 'd']; + arr.objectAt(0); // "a" + arr.objectAt(3); // "d" + arr.objectAt(-1); // undefined + arr.objectAt(4); // undefined + arr.objectAt(5); // undefined + ``` + + @method objectAt + @param {Number} idx The index of the item to return. + @return {*} item at index or undefined + */ + objectAt: function(idx) { + if ((idx < 0) || (idx>=get(this, 'length'))) return undefined ; + return get(this, idx); + }, + + /** + This returns the objects at the specified indexes, using `objectAt`. + + ```javascript + var arr = ['a', 'b', 'c', 'd']; + arr.objectsAt([0, 1, 2]); // ["a", "b", "c"] + arr.objectsAt([2, 3, 4]); // ["c", "d", undefined] + ``` + + @method objectsAt + @param {Array} indexes An array of indexes of items to return. + @return {Array} + */ + objectsAt: function(indexes) { + var self = this; + return map(indexes, function(idx) { return self.objectAt(idx); }); + }, + + // overrides Ember.Enumerable version + nextObject: function(idx) { + return this.objectAt(idx); + }, + + /** + This is the handler for the special array content property. If you get + this property, it will return this. If you set this property it a new + array, it will replace the current content. + + This property overrides the default property defined in `Ember.Enumerable`. + + @property [] + @return this + */ + '[]': Ember.computed(function(key, value) { + if (value !== undefined) this.replace(0, get(this, 'length'), value) ; + return this ; + }), + + firstObject: Ember.computed(function() { + return this.objectAt(0); + }), + + lastObject: Ember.computed(function() { + return this.objectAt(get(this, 'length')-1); + }), + + // optimized version from Enumerable + contains: function(obj) { + return this.indexOf(obj) >= 0; + }, + + // Add any extra methods to Ember.Array that are native to the built-in Array. + /** + Returns a new array that is a slice of the receiver. This implementation + uses the observable array methods to retrieve the objects for the new + slice. + + ```javascript + var arr = ['red', 'green', 'blue']; + arr.slice(0); // ['red', 'green', 'blue'] + arr.slice(0, 2); // ['red', 'green'] + arr.slice(1, 100); // ['green', 'blue'] + ``` + + @method slice + @param {Integer} beginIndex (Optional) index to begin slicing from. + @param {Integer} endIndex (Optional) index to end the slice at. + @return {Array} New array with specified slice + */ + slice: function(beginIndex, endIndex) { + var ret = Ember.A(); + var length = get(this, 'length') ; + if (isNone(beginIndex)) beginIndex = 0 ; + if (isNone(endIndex) || (endIndex > length)) endIndex = length ; + + if (beginIndex < 0) beginIndex = length + beginIndex; + if (endIndex < 0) endIndex = length + endIndex; + + while(beginIndex < endIndex) { + ret[ret.length] = this.objectAt(beginIndex++) ; + } + return ret ; + }, + + /** + Returns the index of the given object's first occurrence. + If no `startAt` argument is given, the starting location to + search is 0. If it's negative, will count backward from + the end of the array. Returns -1 if no match is found. + + ```javascript + var arr = ["a", "b", "c", "d", "a"]; + arr.indexOf("a"); // 0 + arr.indexOf("z"); // -1 + arr.indexOf("a", 2); // 4 + arr.indexOf("a", -1); // 4 + arr.indexOf("b", 3); // -1 + arr.indexOf("a", 100); // -1 + ``` + + @method indexOf + @param {Object} object the item to search for + @param {Number} startAt optional starting location to search, default 0 + @return {Number} index or -1 if not found + */ + indexOf: function(object, startAt) { + var idx, len = get(this, 'length'); + + if (startAt === undefined) startAt = 0; + if (startAt < 0) startAt += len; + + for(idx=startAt;idx= len) startAt = len-1; + if (startAt < 0) startAt += len; + + for(idx=startAt;idx>=0;idx--) { + if (this.objectAt(idx) === object) return idx ; + } + return -1; + }, + + // .......................................................... + // ARRAY OBSERVERS + // + + /** + Adds an array observer to the receiving array. The array observer object + normally must implement two methods: + + * `arrayWillChange(observedObj, start, removeCount, addCount)` - This method will be + called just before the array is modified. + * `arrayDidChange(observedObj, start, removeCount, addCount)` - This method will be + called just after the array is modified. + + Both callbacks will be passed the observed object, starting index of the + change as well a a count of the items to be removed and added. You can use + these callbacks to optionally inspect the array during the change, clear + caches, or do any other bookkeeping necessary. + + In addition to passing a target, you can also include an options hash + which you can use to override the method names that will be invoked on the + target. + + @method addArrayObserver + @param {Object} target The observer object. + @param {Hash} opts Optional hash of configuration options including + `willChange` and `didChange` option. + @return {Ember.Array} receiver + */ + addArrayObserver: function(target, opts) { + var willChange = (opts && opts.willChange) || 'arrayWillChange', + didChange = (opts && opts.didChange) || 'arrayDidChange'; + + var hasObservers = get(this, 'hasArrayObservers'); + if (!hasObservers) Ember.propertyWillChange(this, 'hasArrayObservers'); + Ember.addListener(this, '@array:before', target, willChange); + Ember.addListener(this, '@array:change', target, didChange); + if (!hasObservers) Ember.propertyDidChange(this, 'hasArrayObservers'); + return this; + }, + + /** + Removes an array observer from the object if the observer is current + registered. Calling this method multiple times with the same object will + have no effect. + + @method removeArrayObserver + @param {Object} target The object observing the array. + @param {Hash} opts Optional hash of configuration options including + `willChange` and `didChange` option. + @return {Ember.Array} receiver + */ + removeArrayObserver: function(target, opts) { + var willChange = (opts && opts.willChange) || 'arrayWillChange', + didChange = (opts && opts.didChange) || 'arrayDidChange'; + + var hasObservers = get(this, 'hasArrayObservers'); + if (hasObservers) Ember.propertyWillChange(this, 'hasArrayObservers'); + Ember.removeListener(this, '@array:before', target, willChange); + Ember.removeListener(this, '@array:change', target, didChange); + if (hasObservers) Ember.propertyDidChange(this, 'hasArrayObservers'); + return this; + }, + + /** + Becomes true whenever the array currently has observers watching changes + on the array. + + @property Boolean + */ + hasArrayObservers: Ember.computed(function() { + return Ember.hasListeners(this, '@array:change') || Ember.hasListeners(this, '@array:before'); + }), + + /** + If you are implementing an object that supports `Ember.Array`, call this + method just before the array content changes to notify any observers and + invalidate any related properties. Pass the starting index of the change + as well as a delta of the amounts to change. + + @method arrayContentWillChange + @param {Number} startIdx The starting index in the array that will change. + @param {Number} removeAmt The number of items that will be removed. If you + pass `null` assumes 0 + @param {Number} addAmt The number of items that will be added. If you + pass `null` assumes 0. + @return {Ember.Array} receiver + */ + arrayContentWillChange: function(startIdx, removeAmt, addAmt) { + + // if no args are passed assume everything changes + if (startIdx===undefined) { + startIdx = 0; + removeAmt = addAmt = -1; + } else { + if (removeAmt === undefined) removeAmt=-1; + if (addAmt === undefined) addAmt=-1; + } + + // Make sure the @each proxy is set up if anyone is observing @each + if (Ember.isWatching(this, '@each')) { get(this, '@each'); } + + Ember.sendEvent(this, '@array:before', [this, startIdx, removeAmt, addAmt]); + + var removing, lim; + if (startIdx>=0 && removeAmt>=0 && get(this, 'hasEnumerableObservers')) { + removing = []; + lim = startIdx+removeAmt; + for(var idx=startIdx;idx=0 && addAmt>=0 && get(this, 'hasEnumerableObservers')) { + adding = []; + lim = startIdx+addAmt; + for(var idx=startIdx;idx Ember.TrackedArray instances. We use + // this to lazily recompute indexes for item property observers. + this.trackedArraysByGuid = {}; + + // We suspend observers to ignore replacements from `reset` when totally + // recomputing. Unfortunately we cannot properly suspend the observers + // because we only have the key; instead we make the observers no-ops + this.suspended = false; + + // This is used to coalesce item changes from property observers. + this.changedItems = {}; +} + +function ItemPropertyObserverContext (dependentArray, index, trackedArray) { + Ember.assert("Internal error: trackedArray is null or undefined", trackedArray); + + this.dependentArray = dependentArray; + this.index = index; + this.item = dependentArray.objectAt(index); + this.trackedArray = trackedArray; + this.beforeObserver = null; + this.observer = null; + + this.destroyed = false; +} + +DependentArraysObserver.prototype = { + setValue: function (newValue) { + this.instanceMeta.setValue(newValue, true); + }, + getValue: function () { + return this.instanceMeta.getValue(); + }, + + setupObservers: function (dependentArray, dependentKey) { + Ember.assert("dependent array must be an `Ember.Array`", Ember.Array.detect(dependentArray)); + + this.dependentKeysByGuid[guidFor(dependentArray)] = dependentKey; + + dependentArray.addArrayObserver(this, { + willChange: 'dependentArrayWillChange', + didChange: 'dependentArrayDidChange' + }); + + if (this.cp._itemPropertyKeys[dependentKey]) { + this.setupPropertyObservers(dependentKey, this.cp._itemPropertyKeys[dependentKey]); + } + }, + + teardownObservers: function (dependentArray, dependentKey) { + var itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey] || []; + + delete this.dependentKeysByGuid[guidFor(dependentArray)]; + + this.teardownPropertyObservers(dependentKey, itemPropertyKeys); + + dependentArray.removeArrayObserver(this, { + willChange: 'dependentArrayWillChange', + didChange: 'dependentArrayDidChange' + }); + }, + + suspendArrayObservers: function (callback, binding) { + var oldSuspended = this.suspended; + this.suspended = true; + callback.call(binding); + this.suspended = oldSuspended; + }, + + setupPropertyObservers: function (dependentKey, itemPropertyKeys) { + var dependentArray = get(this.instanceMeta.context, dependentKey), + length = get(dependentArray, 'length'), + observerContexts = new Array(length); + + this.resetTransformations(dependentKey, observerContexts); + + forEach(dependentArray, function (item, index) { + var observerContext = this.createPropertyObserverContext(dependentArray, index, this.trackedArraysByGuid[dependentKey]); + observerContexts[index] = observerContext; + + forEach(itemPropertyKeys, function (propertyKey) { + addBeforeObserver(item, propertyKey, this, observerContext.beforeObserver); + addObserver(item, propertyKey, this, observerContext.observer); + }, this); + }, this); + }, + + teardownPropertyObservers: function (dependentKey, itemPropertyKeys) { + var dependentArrayObserver = this, + trackedArray = this.trackedArraysByGuid[dependentKey], + beforeObserver, + observer, + item; + + if (!trackedArray) { return; } + + trackedArray.apply(function (observerContexts, offset, operation) { + if (operation === Ember.TrackedArray.DELETE) { return; } + + forEach(observerContexts, function (observerContext) { + observerContext.destroyed = true; + beforeObserver = observerContext.beforeObserver; + observer = observerContext.observer; + item = observerContext.item; + + forEach(itemPropertyKeys, function (propertyKey) { + removeBeforeObserver(item, propertyKey, dependentArrayObserver, beforeObserver); + removeObserver(item, propertyKey, dependentArrayObserver, observer); + }); + }); + }); + }, + + createPropertyObserverContext: function (dependentArray, index, trackedArray) { + var observerContext = new ItemPropertyObserverContext(dependentArray, index, trackedArray); + + this.createPropertyObserver(observerContext); + + return observerContext; + }, + + createPropertyObserver: function (observerContext) { + var dependentArrayObserver = this; + + observerContext.beforeObserver = function (obj, keyName) { + return dependentArrayObserver.itemPropertyWillChange(obj, keyName, observerContext.dependentArray, observerContext); + }; + observerContext.observer = function (obj, keyName) { + return dependentArrayObserver.itemPropertyDidChange(obj, keyName, observerContext.dependentArray, observerContext); + }; + }, + + resetTransformations: function (dependentKey, observerContexts) { + this.trackedArraysByGuid[dependentKey] = new Ember.TrackedArray(observerContexts); + }, + + trackAdd: function (dependentKey, index, newItems) { + var trackedArray = this.trackedArraysByGuid[dependentKey]; + if (trackedArray) { + trackedArray.addItems(index, newItems); + } + }, + + trackRemove: function (dependentKey, index, removedCount) { + var trackedArray = this.trackedArraysByGuid[dependentKey]; + + if (trackedArray) { + return trackedArray.removeItems(index, removedCount); + } + + return []; + }, + + updateIndexes: function (trackedArray, array) { + var length = get(array, 'length'); + // OPTIMIZE: we could stop updating once we hit the object whose observer + // fired; ie partially apply the transformations + trackedArray.apply(function (observerContexts, offset, operation) { + // we don't even have observer contexts for removed items, even if we did, + // they no longer have any index in the array + if (operation === Ember.TrackedArray.DELETE) { return; } + if (operation === Ember.TrackedArray.RETAIN && observerContexts.length === length && offset === 0) { + // If we update many items we don't want to walk the array each time: we + // only need to update the indexes at most once per run loop. + return; + } + + forEach(observerContexts, function (context, index) { + context.index = index + offset; + }); + }); + }, + + dependentArrayWillChange: function (dependentArray, index, removedCount, addedCount) { + if (this.suspended) { return; } + + var removedItem = this.callbacks.removedItem, + changeMeta, + guid = guidFor(dependentArray), + dependentKey = this.dependentKeysByGuid[guid], + itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey] || [], + length = get(dependentArray, 'length'), + normalizedIndex = normalizeIndex(index, length, 0), + normalizedRemoveCount = normalizeRemoveCount(normalizedIndex, length, removedCount), + item, + itemIndex, + sliceIndex, + observerContexts; + + observerContexts = this.trackRemove(dependentKey, normalizedIndex, normalizedRemoveCount); + + function removeObservers(propertyKey) { + observerContexts[sliceIndex].destroyed = true; + removeBeforeObserver(item, propertyKey, this, observerContexts[sliceIndex].beforeObserver); + removeObserver(item, propertyKey, this, observerContexts[sliceIndex].observer); + } + + for (sliceIndex = normalizedRemoveCount - 1; sliceIndex >= 0; --sliceIndex) { + itemIndex = normalizedIndex + sliceIndex; + if (itemIndex >= length) { break; } + + item = dependentArray.objectAt(itemIndex); + + forEach(itemPropertyKeys, removeObservers, this); + + changeMeta = createChangeMeta(dependentArray, item, itemIndex, this.instanceMeta.propertyName, this.cp); + this.setValue( removedItem.call( + this.instanceMeta.context, this.getValue(), item, changeMeta, this.instanceMeta.sugarMeta)); + } + }, + + dependentArrayDidChange: function (dependentArray, index, removedCount, addedCount) { + if (this.suspended) { return; } + + var addedItem = this.callbacks.addedItem, + guid = guidFor(dependentArray), + dependentKey = this.dependentKeysByGuid[guid], + observerContexts = new Array(addedCount), + itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey], + length = get(dependentArray, 'length'), + normalizedIndex = normalizeIndex(index, length, addedCount), + changeMeta, + observerContext; + + forEach(dependentArray.slice(normalizedIndex, normalizedIndex + addedCount), function (item, sliceIndex) { + if (itemPropertyKeys) { + observerContext = + observerContexts[sliceIndex] = + this.createPropertyObserverContext(dependentArray, normalizedIndex + sliceIndex, this.trackedArraysByGuid[dependentKey]); + forEach(itemPropertyKeys, function (propertyKey) { + addBeforeObserver(item, propertyKey, this, observerContext.beforeObserver); + addObserver(item, propertyKey, this, observerContext.observer); + }, this); + } + + changeMeta = createChangeMeta(dependentArray, item, normalizedIndex + sliceIndex, this.instanceMeta.propertyName, this.cp); + this.setValue( addedItem.call( + this.instanceMeta.context, this.getValue(), item, changeMeta, this.instanceMeta.sugarMeta)); + }, this); + + this.trackAdd(dependentKey, normalizedIndex, observerContexts); + }, + + itemPropertyWillChange: function (obj, keyName, array, observerContext) { + var guid = guidFor(obj); + + if (!this.changedItems[guid]) { + this.changedItems[guid] = { + array: array, + observerContext: observerContext, + obj: obj, + previousValues: {} + }; + } + + this.changedItems[guid].previousValues[keyName] = get(obj, keyName); + }, + + itemPropertyDidChange: function(obj, keyName, array, observerContext) { + this.flushChanges(); + }, + + flushChanges: function() { + var changedItems = this.changedItems, key, c, changeMeta; + + for (key in changedItems) { + c = changedItems[key]; + if (c.observerContext.destroyed) { continue; } + + this.updateIndexes(c.observerContext.trackedArray, c.observerContext.dependentArray); + + changeMeta = createChangeMeta(c.array, c.obj, c.observerContext.index, this.instanceMeta.propertyName, this.cp, c.previousValues); + this.setValue( + this.callbacks.removedItem.call(this.instanceMeta.context, this.getValue(), c.obj, changeMeta, this.instanceMeta.sugarMeta)); + this.setValue( + this.callbacks.addedItem.call(this.instanceMeta.context, this.getValue(), c.obj, changeMeta, this.instanceMeta.sugarMeta)); + } + this.changedItems = {}; + } +}; + +function normalizeIndex(index, length, newItemsOffset) { + if (index < 0) { + return Math.max(0, length + index); + } else if (index < length) { + return index; + } else /* index > length */ { + return Math.min(length - newItemsOffset, index); + } +} + +function normalizeRemoveCount(index, length, removedCount) { + return Math.min(removedCount, length - index); +} + +function createChangeMeta(dependentArray, item, index, propertyName, property, previousValues) { + var meta = { + arrayChanged: dependentArray, + index: index, + item: item, + propertyName: propertyName, + property: property + }; + + if (previousValues) { + // previous values only available for item property changes + meta.previousValues = previousValues; + } + + return meta; +} + +function addItems (dependentArray, callbacks, cp, propertyName, meta) { + forEach(dependentArray, function (item, index) { + meta.setValue( callbacks.addedItem.call( + this, meta.getValue(), item, createChangeMeta(dependentArray, item, index, propertyName, cp), meta.sugarMeta)); + }, this); +} + +function reset(cp, propertyName) { + var callbacks = cp._callbacks(), + meta; + + if (cp._hasInstanceMeta(this, propertyName)) { + meta = cp._instanceMeta(this, propertyName); + meta.setValue(cp.resetValue(meta.getValue())); + } else { + meta = cp._instanceMeta(this, propertyName); + } + + if (cp.options.initialize) { + cp.options.initialize.call(this, meta.getValue(), { property: cp, propertyName: propertyName }, meta.sugarMeta); + } +} + +function ReduceComputedPropertyInstanceMeta(context, propertyName, initialValue) { + this.context = context; + this.propertyName = propertyName; + this.cache = metaFor(context).cache; + + this.dependentArrays = {}; + this.sugarMeta = {}; + + this.initialValue = initialValue; +} + +ReduceComputedPropertyInstanceMeta.prototype = { + getValue: function () { + if (this.propertyName in this.cache) { + return this.cache[this.propertyName]; + } else { + return this.initialValue; + } + }, + + setValue: function(newValue, triggerObservers) { + // This lets sugars force a recomputation, handy for very simple + // implementations of eg max. + if (newValue !== undefined) { + var fireObservers = triggerObservers && (newValue !== this.cache[this.propertyName]); + + if (fireObservers) { + propertyWillChange(this.context, this.propertyName); + } + + this.cache[this.propertyName] = newValue; + + if (fireObservers) { + propertyDidChange(this.context, this.propertyName); + } + } else { + delete this.cache[this.propertyName]; + } + } +}; + +/** + A computed property whose dependent keys are arrays and which is updated with + "one at a time" semantics. + + @class ReduceComputedProperty + @namespace Ember + @extends Ember.ComputedProperty + @constructor +*/ +function ReduceComputedProperty(options) { + var cp = this; + + this.options = options; + this._instanceMetas = {}; + + this._dependentKeys = null; + // A map of dependentKey -> [itemProperty, ...] that tracks what properties of + // items in the array we must track to update this property. + this._itemPropertyKeys = {}; + this._previousItemPropertyKeys = {}; + + this.readOnly(); + this.cacheable(); + + this.recomputeOnce = function(propertyName) { + // What we really want to do is coalesce by . + // We need a form of `scheduleOnce` that accepts an arbitrary token to + // coalesce by, in addition to the target and method. + Ember.run.once(this, recompute, propertyName); + }; + var recompute = function(propertyName) { + var dependentKeys = cp._dependentKeys, + meta = cp._instanceMeta(this, propertyName), + callbacks = cp._callbacks(); + + reset.call(this, cp, propertyName); + + meta.dependentArraysObserver.suspendArrayObservers(function () { + forEach(cp._dependentKeys, function (dependentKey) { + var dependentArray = get(this, dependentKey), + previousDependentArray = meta.dependentArrays[dependentKey]; + + if (dependentArray === previousDependentArray) { + // The array may be the same, but our item property keys may have + // changed, so we set them up again. We can't easily tell if they've + // changed: the array may be the same object, but with different + // contents. + if (cp._previousItemPropertyKeys[dependentKey]) { + delete cp._previousItemPropertyKeys[dependentKey]; + meta.dependentArraysObserver.setupPropertyObservers(dependentKey, cp._itemPropertyKeys[dependentKey]); + } + } else { + meta.dependentArrays[dependentKey] = dependentArray; + + if (previousDependentArray) { + meta.dependentArraysObserver.teardownObservers(previousDependentArray, dependentKey); + } + + if (dependentArray) { + meta.dependentArraysObserver.setupObservers(dependentArray, dependentKey); + } + } + }, this); + }, this); + + forEach(cp._dependentKeys, function(dependentKey) { + var dependentArray = get(this, dependentKey); + if (dependentArray) { + addItems.call(this, dependentArray, callbacks, cp, propertyName, meta); + } + }, this); + }; + + this.func = function (propertyName) { + Ember.assert("Computed reduce values require at least one dependent key", cp._dependentKeys); + + recompute.call(this, propertyName); + + return cp._instanceMeta(this, propertyName).getValue(); + }; +} + +Ember.ReduceComputedProperty = ReduceComputedProperty; +ReduceComputedProperty.prototype = o_create(ComputedProperty.prototype); + +function defaultCallback(computedValue) { + return computedValue; +} + +ReduceComputedProperty.prototype._callbacks = function () { + if (!this.callbacks) { + var options = this.options; + this.callbacks = { + removedItem: options.removedItem || defaultCallback, + addedItem: options.addedItem || defaultCallback + }; + } + return this.callbacks; +}; + +ReduceComputedProperty.prototype._hasInstanceMeta = function (context, propertyName) { + var guid = guidFor(context), + key = guid + ':' + propertyName; + + return !!this._instanceMetas[key]; +}; + +ReduceComputedProperty.prototype._instanceMeta = function (context, propertyName) { + var guid = guidFor(context), + key = guid + ':' + propertyName, + meta = this._instanceMetas[key]; + + if (!meta) { + meta = this._instanceMetas[key] = new ReduceComputedPropertyInstanceMeta(context, propertyName, this.initialValue()); + meta.dependentArraysObserver = new DependentArraysObserver(this._callbacks(), this, meta, context, propertyName, meta.sugarMeta); + } + + return meta; +}; + +ReduceComputedProperty.prototype.initialValue = function () { + if (typeof this.options.initialValue === 'function') { + return this.options.initialValue(); + } + else { + return this.options.initialValue; + } +}; + +ReduceComputedProperty.prototype.resetValue = function (value) { + return this.initialValue(); +}; + +ReduceComputedProperty.prototype.itemPropertyKey = function (dependentArrayKey, itemPropertyKey) { + this._itemPropertyKeys[dependentArrayKey] = this._itemPropertyKeys[dependentArrayKey] || []; + this._itemPropertyKeys[dependentArrayKey].push(itemPropertyKey); +}; + +ReduceComputedProperty.prototype.clearItemPropertyKeys = function (dependentArrayKey) { + if (this._itemPropertyKeys[dependentArrayKey]) { + this._previousItemPropertyKeys[dependentArrayKey] = this._itemPropertyKeys[dependentArrayKey]; + this._itemPropertyKeys[dependentArrayKey] = []; + } +}; + +ReduceComputedProperty.prototype.property = function () { + var cp = this, + args = a_slice.call(arguments), + propertyArgs = new Ember.Set(), + match, + dependentArrayKey, + itemPropertyKey; + + forEach(a_slice.call(arguments), function (dependentKey) { + if (doubleEachPropertyPattern.test(dependentKey)) { + throw new Ember.Error("Nested @each properties not supported: " + dependentKey); + } else if (match = eachPropertyPattern.exec(dependentKey)) { + dependentArrayKey = match[1]; + itemPropertyKey = match[2]; + cp.itemPropertyKey(dependentArrayKey, itemPropertyKey); + propertyArgs.add(dependentArrayKey); + } else { + propertyArgs.add(dependentKey); + } + }); + + return ComputedProperty.prototype.property.apply(this, propertyArgs.toArray()); +}; + +/** + Creates a computed property which operates on dependent arrays and + is updated with "one at a time" semantics. When items are added or + removed from the dependent array(s) a reduce computed only operates + on the change instead of re-evaluating the entire array. + + If there are more than one arguments the first arguments are + considered to be dependent property keys. The last argument is + required to be an options object. The options object can have the + following four properties: + + `initialValue` - A value or function that will be used as the initial + value for the computed. If this property is a function the result of calling + the function will be used as the initial value. This property is required. + + `initialize` - An optional initialize function. Typically this will be used + to set up state on the instanceMeta object. + + `removedItem` - A function that is called each time an element is removed + from the array. + + `addedItem` - A function that is called each time an element is added to + the array. + + + The `initialize` function has the following signature: + + ```javascript + function (initialValue, changeMeta, instanceMeta) + ``` + + `initialValue` - The value of the `initialValue` property from the + options object. + + `changeMeta` - An object which contains meta information about the + computed. It contains the following properties: + + - `property` the computed property + - `propertyName` the name of the property on the object + + `instanceMeta` - An object that can be used to store meta + information needed for calculating your computed. For example a + unique computed might use this to store the number of times a given + element is found in the dependent array. + + + The `removedItem` and `addedItem` functions both have the following signature: + + ```javascript + function (accumulatedValue, item, changeMeta, instanceMeta) + ``` + + `accumulatedValue` - The value returned from the last time + `removedItem` or `addedItem` was called or `initialValue`. + + `item` - the element added or removed from the array + + `changeMeta` - An object which contains meta information about the + change. It contains the following properties: + + - `property` the computed property + - `propertyName` the name of the property on the object + - `index` the index of the added or removed item + - `item` the added or removed item: this is exactly the same as + the second arg + - `arrayChanged` the array that triggered the change. Can be + useful when depending on multiple arrays. + + For property changes triggered on an item property change (when + depKey is something like `someArray.@each.someProperty`), + `changeMeta` will also contain the following property: + + - `previousValues` an object whose keys are the properties that changed on + the item, and whose values are the item's previous values. + + `previousValues` is important Ember coalesces item property changes via + Ember.run.once. This means that by the time removedItem gets called, item has + the new values, but you may need the previous value (eg for sorting & + filtering). + + `instanceMeta` - An object that can be used to store meta + information needed for calculating your computed. For example a + unique computed might use this to store the number of times a given + element is found in the dependent array. + + The `removedItem` and `addedItem` functions should return the accumulated + value. It is acceptable to not return anything (ie return undefined) + to invalidate the computation. This is generally not a good idea for + arrayComputed but it's used in eg max and min. + + Note that observers will be fired if either of these functions return a value + that differs from the accumulated value. When returning an object that + mutates in response to array changes, for example an array that maps + everything from some other array (see `Ember.computed.map`), it is usually + important that the *same* array be returned to avoid accidentally triggering observers. + + Example + + ```javascript + Ember.computed.max = function (dependentKey) { + return Ember.reduceComputed.call(null, dependentKey, { + initialValue: -Infinity, + + addedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { + return Math.max(accumulatedValue, item); + }, + + removedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { + if (item < accumulatedValue) { + return accumulatedValue; + } + } + }); + }; + ``` + + Dependent keys may refer to `@this` to observe changes to the object itself, + which must be array-like, rather than a property of the object. This is + mostly useful for array proxies, to ensure objects are retrieved via + `objectAtContent`. This is how you could sort items by properties defined on an item controller. + + Example + + ```javascript + App.PeopleController = Ember.ArrayController.extend({ + itemController: 'person', + + sortedPeople: Ember.computed.sort('@this.@each.reversedName', function(personA, personB) { + // `reversedName` isn't defined on Person, but we have access to it via + // the item controller App.PersonController. If we'd used + // `content.@each.reversedName` above, we would be getting the objects + // directly and not have access to `reversedName`. + // + var reversedNameA = get(personA, 'reversedName'), + reversedNameB = get(personB, 'reversedName'); + + return Ember.compare(reversedNameA, reversedNameB); + }) + }); + + App.PersonController = Ember.ObjectController.extend({ + reversedName: function () { + return reverse(get(this, 'name')); + }.property('name') + }) + ``` + + @method reduceComputed + @for Ember + @param {String} [dependentKeys*] + @param {Object} options + @return {Ember.ComputedProperty} +*/ +Ember.reduceComputed = function (options) { + var args; + + if (arguments.length > 1) { + args = a_slice.call(arguments, 0, -1); + options = a_slice.call(arguments, -1)[0]; + } + + if (typeof options !== "object") { + throw new Ember.Error("Reduce Computed Property declared without an options hash"); + } + + if (!('initialValue' in options)) { + throw new Ember.Error("Reduce Computed Property declared without an initial value"); + } + + var cp = new ReduceComputedProperty(options); + + if (args) { + cp.property.apply(cp, args); + } + + return cp; +}; + +})(); + + + +(function() { +var ReduceComputedProperty = Ember.ReduceComputedProperty, + a_slice = [].slice, + o_create = Ember.create, + forEach = Ember.EnumerableUtils.forEach; + +function ArrayComputedProperty() { + var cp = this; + + ReduceComputedProperty.apply(this, arguments); + + this.func = (function(reduceFunc) { + return function (propertyName) { + if (!cp._hasInstanceMeta(this, propertyName)) { + // When we recompute an array computed property, we need already + // retrieved arrays to be updated; we can't simply empty the cache and + // hope the array is re-retrieved. + forEach(cp._dependentKeys, function(dependentKey) { + Ember.addObserver(this, dependentKey, function() { + cp.recomputeOnce.call(this, propertyName); + }); + }, this); + } + + return reduceFunc.apply(this, arguments); + }; + })(this.func); + + return this; +} +Ember.ArrayComputedProperty = ArrayComputedProperty; +ArrayComputedProperty.prototype = o_create(ReduceComputedProperty.prototype); +ArrayComputedProperty.prototype.initialValue = function () { + return Ember.A(); +}; +ArrayComputedProperty.prototype.resetValue = function (array) { + array.clear(); + return array; +}; + +/** + Creates a computed property which operates on dependent arrays and + is updated with "one at a time" semantics. When items are added or + removed from the dependent array(s) an array computed only operates + on the change instead of re-evaluating the entire array. This should + return an array, if you'd like to use "one at a time" semantics and + compute some value other then an array look at + `Ember.reduceComputed`. + + If there are more than one arguments the first arguments are + considered to be dependent property keys. The last argument is + required to be an options object. The options object can have the + following three properties. + + `initialize` - An optional initialize function. Typically this will be used + to set up state on the instanceMeta object. + + `removedItem` - A function that is called each time an element is + removed from the array. + + `addedItem` - A function that is called each time an element is + added to the array. + + + The `initialize` function has the following signature: + + ```javascript + function (array, changeMeta, instanceMeta) + ``` + + `array` - The initial value of the arrayComputed, an empty array. + + `changeMeta` - An object which contains meta information about the + computed. It contains the following properties: + + - `property` the computed property + - `propertyName` the name of the property on the object + + `instanceMeta` - An object that can be used to store meta + information needed for calculating your computed. For example a + unique computed might use this to store the number of times a given + element is found in the dependent array. + + + The `removedItem` and `addedItem` functions both have the following signature: + + ```javascript + function (accumulatedValue, item, changeMeta, instanceMeta) + ``` + + `accumulatedValue` - The value returned from the last time + `removedItem` or `addedItem` was called or an empty array. + + `item` - the element added or removed from the array + + `changeMeta` - An object which contains meta information about the + change. It contains the following properties: + + - `property` the computed property + - `propertyName` the name of the property on the object + - `index` the index of the added or removed item + - `item` the added or removed item: this is exactly the same as + the second arg + - `arrayChanged` the array that triggered the change. Can be + useful when depending on multiple arrays. + + For property changes triggered on an item property change (when + depKey is something like `someArray.@each.someProperty`), + `changeMeta` will also contain the following property: + + - `previousValues` an object whose keys are the properties that changed on + the item, and whose values are the item's previous values. + + `previousValues` is important Ember coalesces item property changes via + Ember.run.once. This means that by the time removedItem gets called, item has + the new values, but you may need the previous value (eg for sorting & + filtering). + + `instanceMeta` - An object that can be used to store meta + information needed for calculating your computed. For example a + unique computed might use this to store the number of times a given + element is found in the dependent array. + + The `removedItem` and `addedItem` functions should return the accumulated + value. It is acceptable to not return anything (ie return undefined) + to invalidate the computation. This is generally not a good idea for + arrayComputed but it's used in eg max and min. + + Example + + ```javascript + Ember.computed.map = function(dependentKey, callback) { + var options = { + addedItem: function(array, item, changeMeta, instanceMeta) { + var mapped = callback(item); + array.insertAt(changeMeta.index, mapped); + return array; + }, + removedItem: function(array, item, changeMeta, instanceMeta) { + array.removeAt(changeMeta.index, 1); + return array; + } + }; + + return Ember.arrayComputed(dependentKey, options); + }; + ``` + + @method arrayComputed + @for Ember + @param {String} [dependentKeys*] + @param {Object} options + @return {Ember.ComputedProperty} +*/ +Ember.arrayComputed = function (options) { + var args; + + if (arguments.length > 1) { + args = a_slice.call(arguments, 0, -1); + options = a_slice.call(arguments, -1)[0]; + } + + if (typeof options !== "object") { + throw new Ember.Error("Array Computed Property declared without an options hash"); + } + + var cp = new ArrayComputedProperty(options); + + if (args) { + cp.property.apply(cp, args); + } + + return cp; +}; + +})(); + + + +(function() { +/** +@module ember +@submodule ember-runtime +*/ + +var get = Ember.get, + set = Ember.set, + guidFor = Ember.guidFor, + merge = Ember.merge, + a_slice = [].slice, + forEach = Ember.EnumerableUtils.forEach, + map = Ember.EnumerableUtils.map, + SearchProxy; + +/** + A computed property that calculates the maximum value in the + dependent array. This will return `-Infinity` when the dependent + array is empty. + + Example + + ```javascript + App.Person = Ember.Object.extend({ + childAges: Ember.computed.mapBy('children', 'age'), + maxChildAge: Ember.computed.max('childAges') + }); + + var lordByron = App.Person.create({children: []}); + lordByron.get('maxChildAge'); // -Infinity + lordByron.get('children').pushObject({name: 'Augusta Ada Byron', age: 7}); + lordByron.get('maxChildAge'); // 7 + lordByron.get('children').pushObjects([{name: 'Allegra Byron', age: 5}, {name: 'Elizabeth Medora Leigh', age: 8}]); + lordByron.get('maxChildAge'); // 8 + ``` + + @method computed.max + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computes the largest value in the dependentKey's array +*/ +Ember.computed.max = function (dependentKey) { + return Ember.reduceComputed.call(null, dependentKey, { + initialValue: -Infinity, + + addedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { + return Math.max(accumulatedValue, item); + }, + + removedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { + if (item < accumulatedValue) { + return accumulatedValue; + } + } + }); +}; + +/** + A computed property that calculates the minimum value in the + dependent array. This will return `Infinity` when the dependent + array is empty. + + Example + + ```javascript + App.Person = Ember.Object.extend({ + childAges: Ember.computed.mapBy('children', 'age'), + minChildAge: Ember.computed.min('childAges') + }); + + var lordByron = App.Person.create({children: []}); + lordByron.get('minChildAge'); // Infinity + lordByron.get('children').pushObject({name: 'Augusta Ada Byron', age: 7}); + lordByron.get('minChildAge'); // 7 + lordByron.get('children').pushObjects([{name: 'Allegra Byron', age: 5}, {name: 'Elizabeth Medora Leigh', age: 8}]); + lordByron.get('minChildAge'); // 5 + ``` + + @method computed.min + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computes the smallest value in the dependentKey's array +*/ +Ember.computed.min = function (dependentKey) { + return Ember.reduceComputed.call(null, dependentKey, { + initialValue: Infinity, + + addedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { + return Math.min(accumulatedValue, item); + }, + + removedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { + if (item > accumulatedValue) { + return accumulatedValue; + } + } + }); +}; + +/** + Returns an array mapped via the callback + + The callback method you provide should have the following signature: + + ```javascript + function(item); + ``` + + - `item` is the current item in the iteration. + + Example + + ```javascript + App.Hamster = Ember.Object.extend({ + excitingChores: Ember.computed.map('chores', function(chore) { + return chore.toUpperCase() + '!'; + }) + }); + + var hamster = App.Hamster.create({chores: ['cook', 'clean', 'write more unit tests']}); + hamster.get('excitingChores'); // ['COOK!', 'CLEAN!', 'WRITE MORE UNIT TESTS!'] + ``` + + @method computed.map + @for Ember + @param {String} dependentKey + @param {Function} callback + @return {Ember.ComputedProperty} an array mapped via the callback +*/ +Ember.computed.map = function(dependentKey, callback) { + var options = { + addedItem: function(array, item, changeMeta, instanceMeta) { + var mapped = callback.call(this, item); + array.insertAt(changeMeta.index, mapped); + return array; + }, + removedItem: function(array, item, changeMeta, instanceMeta) { + array.removeAt(changeMeta.index, 1); + return array; + } + }; + + return Ember.arrayComputed(dependentKey, options); +}; + +/** + Returns an array mapped to the specified key. + + Example + + ```javascript + App.Person = Ember.Object.extend({ + childAges: Ember.computed.mapBy('children', 'age') + }); + + var lordByron = App.Person.create({children: []}); + lordByron.get('childAges'); // [] + lordByron.get('children').pushObject({name: 'Augusta Ada Byron', age: 7}); + lordByron.get('childAges'); // [7] + lordByron.get('children').pushObjects([{name: 'Allegra Byron', age: 5}, {name: 'Elizabeth Medora Leigh', age: 8}]); + lordByron.get('childAges'); // [7, 5, 8] + ``` + + @method computed.mapBy + @for Ember + @param {String} dependentKey + @param {String} propertyKey + @return {Ember.ComputedProperty} an array mapped to the specified key +*/ +Ember.computed.mapBy = function(dependentKey, propertyKey) { + var callback = function(item) { return get(item, propertyKey); }; + return Ember.computed.map(dependentKey + '.@each.' + propertyKey, callback); +}; + +/** + @method computed.mapProperty + @for Ember + @deprecated Use `Ember.computed.mapBy` instead + @param dependentKey + @param propertyKey +*/ +Ember.computed.mapProperty = Ember.computed.mapBy; + +/** + Filters the array by the callback. + + The callback method you provide should have the following signature: + + ```javascript + function(item); + ``` + + - `item` is the current item in the iteration. + + Example + + ```javascript + App.Hamster = Ember.Object.extend({ + remainingChores: Ember.computed.filter('chores', function(chore) { + return !chore.done; + }) + }); + + var hamster = App.Hamster.create({chores: [ + {name: 'cook', done: true}, + {name: 'clean', done: true}, + {name: 'write more unit tests', done: false} + ]}); + hamster.get('remainingChores'); // [{name: 'write more unit tests', done: false}] + ``` + + @method computed.filter + @for Ember + @param {String} dependentKey + @param {Function} callback + @return {Ember.ComputedProperty} the filtered array +*/ +Ember.computed.filter = function(dependentKey, callback) { + var options = { + initialize: function (array, changeMeta, instanceMeta) { + instanceMeta.filteredArrayIndexes = new Ember.SubArray(); + }, + + addedItem: function(array, item, changeMeta, instanceMeta) { + var match = !!callback.call(this, item), + filterIndex = instanceMeta.filteredArrayIndexes.addItem(changeMeta.index, match); + + if (match) { + array.insertAt(filterIndex, item); + } + + return array; + }, + + removedItem: function(array, item, changeMeta, instanceMeta) { + var filterIndex = instanceMeta.filteredArrayIndexes.removeItem(changeMeta.index); + + if (filterIndex > -1) { + array.removeAt(filterIndex); + } + + return array; + } + }; + + return Ember.arrayComputed(dependentKey, options); +}; + +/** + Filters the array by the property and value + + Example + + ```javascript + App.Hamster = Ember.Object.extend({ + remainingChores: Ember.computed.filterBy('chores', 'done', false) + }); + + var hamster = App.Hamster.create({chores: [ + {name: 'cook', done: true}, + {name: 'clean', done: true}, + {name: 'write more unit tests', done: false} + ]}); + hamster.get('remainingChores'); // [{name: 'write more unit tests', done: false}] + ``` + + @method computed.filterBy + @for Ember + @param {String} dependentKey + @param {String} propertyKey + @param {String} value + @return {Ember.ComputedProperty} the filtered array +*/ +Ember.computed.filterBy = function(dependentKey, propertyKey, value) { + var callback; + + if (arguments.length === 2) { + callback = function(item) { + return get(item, propertyKey); + }; + } else { + callback = function(item) { + return get(item, propertyKey) === value; + }; + } + + return Ember.computed.filter(dependentKey + '.@each.' + propertyKey, callback); +}; + +/** + @method computed.filterProperty + @for Ember + @param dependentKey + @param propertyKey + @param value + @deprecated Use `Ember.computed.filterBy` instead +*/ +Ember.computed.filterProperty = Ember.computed.filterBy; + +/** + A computed property which returns a new array with all the unique + elements from one or more dependent arrays. + + Example + + ```javascript + App.Hamster = Ember.Object.extend({ + uniqueFruits: Ember.computed.uniq('fruits') + }); + + var hamster = App.Hamster.create({fruits: [ + 'banana', + 'grape', + 'kale', + 'banana' + ]}); + hamster.get('uniqueFruits'); // ['banana', 'grape', 'kale'] + ``` + + @method computed.uniq + @for Ember + @param {String} propertyKey* + @return {Ember.ComputedProperty} computes a new array with all the + unique elements from the dependent array +*/ +Ember.computed.uniq = function() { + var args = a_slice.call(arguments); + args.push({ + initialize: function(array, changeMeta, instanceMeta) { + instanceMeta.itemCounts = {}; + }, + + addedItem: function(array, item, changeMeta, instanceMeta) { + var guid = guidFor(item); + + if (!instanceMeta.itemCounts[guid]) { + instanceMeta.itemCounts[guid] = 1; + } else { + ++instanceMeta.itemCounts[guid]; + } + array.addObject(item); + return array; + }, + removedItem: function(array, item, _, instanceMeta) { + var guid = guidFor(item), + itemCounts = instanceMeta.itemCounts; + + if (--itemCounts[guid] === 0) { + array.removeObject(item); + } + return array; + } + }); + return Ember.arrayComputed.apply(null, args); +}; + +/** + Alias for [Ember.computed.uniq](/api/#method_computed_uniq). + + @method computed.union + @for Ember + @param {String} propertyKey* + @return {Ember.ComputedProperty} computes a new array with all the + unique elements from the dependent array +*/ +Ember.computed.union = Ember.computed.uniq; + +/** + A computed property which returns a new array with all the duplicated + elements from two or more dependeny arrays. + + Example + + ```javascript + var obj = Ember.Object.createWithMixins({ + adaFriends: ['Charles Babbage', 'John Hobhouse', 'William King', 'Mary Somerville'], + charlesFriends: ['William King', 'Mary Somerville', 'Ada Lovelace', 'George Peacock'], + friendsInCommon: Ember.computed.intersect('adaFriends', 'charlesFriends') + }); + + obj.get('friendsInCommon'); // ['William King', 'Mary Somerville'] + ``` + + @method computed.intersect + @for Ember + @param {String} propertyKey* + @return {Ember.ComputedProperty} computes a new array with all the + duplicated elements from the dependent arrays +*/ +Ember.computed.intersect = function () { + var getDependentKeyGuids = function (changeMeta) { + return map(changeMeta.property._dependentKeys, function (dependentKey) { + return guidFor(dependentKey); + }); + }; + + var args = a_slice.call(arguments); + args.push({ + initialize: function (array, changeMeta, instanceMeta) { + instanceMeta.itemCounts = {}; + }, + + addedItem: function(array, item, changeMeta, instanceMeta) { + var itemGuid = guidFor(item), + dependentGuids = getDependentKeyGuids(changeMeta), + dependentGuid = guidFor(changeMeta.arrayChanged), + numberOfDependentArrays = changeMeta.property._dependentKeys.length, + itemCounts = instanceMeta.itemCounts; + + if (!itemCounts[itemGuid]) { itemCounts[itemGuid] = {}; } + if (itemCounts[itemGuid][dependentGuid] === undefined) { itemCounts[itemGuid][dependentGuid] = 0; } + + if (++itemCounts[itemGuid][dependentGuid] === 1 && + numberOfDependentArrays === Ember.keys(itemCounts[itemGuid]).length) { + + array.addObject(item); + } + return array; + }, + removedItem: function(array, item, changeMeta, instanceMeta) { + var itemGuid = guidFor(item), + dependentGuids = getDependentKeyGuids(changeMeta), + dependentGuid = guidFor(changeMeta.arrayChanged), + numberOfDependentArrays = changeMeta.property._dependentKeys.length, + numberOfArraysItemAppearsIn, + itemCounts = instanceMeta.itemCounts; + + if (itemCounts[itemGuid][dependentGuid] === undefined) { itemCounts[itemGuid][dependentGuid] = 0; } + if (--itemCounts[itemGuid][dependentGuid] === 0) { + delete itemCounts[itemGuid][dependentGuid]; + numberOfArraysItemAppearsIn = Ember.keys(itemCounts[itemGuid]).length; + + if (numberOfArraysItemAppearsIn === 0) { + delete itemCounts[itemGuid]; + } + array.removeObject(item); + } + return array; + } + }); + return Ember.arrayComputed.apply(null, args); +}; + +/** + A computed property which returns a new array with all the + properties from the first dependent array that are not in the second + dependent array. + + Example + + ```javascript + App.Hamster = Ember.Object.extend({ + likes: ['banana', 'grape', 'kale'], + wants: Ember.computed.setDiff('likes', 'fruits') + }); + + var hamster = App.Hamster.create({fruits: [ + 'grape', + 'kale', + ]}); + hamster.get('wants'); // ['banana'] + ``` + + @method computed.setDiff + @for Ember + @param {String} setAProperty + @param {String} setBProperty + @return {Ember.ComputedProperty} computes a new array with all the + items from the first dependent array that are not in the second + dependent array +*/ +Ember.computed.setDiff = function (setAProperty, setBProperty) { + if (arguments.length !== 2) { + throw new Ember.Error("setDiff requires exactly two dependent arrays."); + } + return Ember.arrayComputed.call(null, setAProperty, setBProperty, { + addedItem: function (array, item, changeMeta, instanceMeta) { + var setA = get(this, setAProperty), + setB = get(this, setBProperty); + + if (changeMeta.arrayChanged === setA) { + if (!setB.contains(item)) { + array.addObject(item); + } + } else { + array.removeObject(item); + } + return array; + }, + + removedItem: function (array, item, changeMeta, instanceMeta) { + var setA = get(this, setAProperty), + setB = get(this, setBProperty); + + if (changeMeta.arrayChanged === setB) { + if (setA.contains(item)) { + array.addObject(item); + } + } else { + array.removeObject(item); + } + return array; + } + }); +}; + +function binarySearch(array, item, low, high) { + var mid, midItem, res, guidMid, guidItem; + + if (arguments.length < 4) { high = get(array, 'length'); } + if (arguments.length < 3) { low = 0; } + + if (low === high) { + return low; + } + + mid = low + Math.floor((high - low) / 2); + midItem = array.objectAt(mid); + + guidMid = _guidFor(midItem); + guidItem = _guidFor(item); + + if (guidMid === guidItem) { + return mid; + } + + res = this.order(midItem, item); + if (res === 0) { + res = guidMid < guidItem ? -1 : 1; + } + + + if (res < 0) { + return this.binarySearch(array, item, mid+1, high); + } else if (res > 0) { + return this.binarySearch(array, item, low, mid); + } + + return mid; + + function _guidFor(item) { + if (SearchProxy.detectInstance(item)) { + return guidFor(get(item, 'content')); + } + return guidFor(item); + } +} + + +SearchProxy = Ember.ObjectProxy.extend(); + +/** + A computed property which returns a new array with all the + properties from the first dependent array sorted based on a property + or sort function. + + The callback method you provide should have the following signature: + + ```javascript + function(itemA, itemB); + ``` + + - `itemA` the first item to compare. + - `itemB` the second item to compare. + + This function should return `-1` when `itemA` should come before + `itemB`. It should return `1` when `itemA` should come after + `itemB`. If the `itemA` and `itemB` are equal this function should return `0`. + + Example + + ```javascript + var ToDoList = Ember.Object.extend({ + todosSorting: ['name'], + sortedTodos: Ember.computed.sort('todos', 'todosSorting'), + priorityTodos: Ember.computed.sort('todos', function(a, b){ + if (a.priority > b.priority) { + return 1; + } else if (a.priority < b.priority) { + return -1; + } + return 0; + }), + }); + var todoList = ToDoList.create({todos: [ + {name: 'Unit Test', priority: 2}, + {name: 'Documentation', priority: 3}, + {name: 'Release', priority: 1} + ]}); + + todoList.get('sortedTodos'); // [{name:'Documentation', priority:3}, {name:'Release', priority:1}, {name:'Unit Test', priority:2}] + todoList.get('priorityTodos'); // [{name:'Release', priority:1}, {name:'Unit Test', priority:2}, {name:'Documentation', priority:3}] + ``` + + @method computed.sort + @for Ember + @param {String} dependentKey + @param {String or Function} sortDefinition a dependent key to an + array of sort properties or a function to use when sorting + @return {Ember.ComputedProperty} computes a new sorted array based + on the sort property array or callback function +*/ +Ember.computed.sort = function (itemsKey, sortDefinition) { + Ember.assert("Ember.computed.sort requires two arguments: an array key to sort and either a sort properties key or sort function", arguments.length === 2); + + var initFn, sortPropertiesKey; + + if (typeof sortDefinition === 'function') { + initFn = function (array, changeMeta, instanceMeta) { + instanceMeta.order = sortDefinition; + instanceMeta.binarySearch = binarySearch; + }; + } else { + sortPropertiesKey = sortDefinition; + initFn = function (array, changeMeta, instanceMeta) { + function setupSortProperties() { + var sortPropertyDefinitions = get(this, sortPropertiesKey), + sortProperty, + sortProperties = instanceMeta.sortProperties = [], + sortPropertyAscending = instanceMeta.sortPropertyAscending = {}, + idx, + asc; + + Ember.assert("Cannot sort: '" + sortPropertiesKey + "' is not an array.", Ember.isArray(sortPropertyDefinitions)); + + changeMeta.property.clearItemPropertyKeys(itemsKey); + + forEach(sortPropertyDefinitions, function (sortPropertyDefinition) { + if ((idx = sortPropertyDefinition.indexOf(':')) !== -1) { + sortProperty = sortPropertyDefinition.substring(0, idx); + asc = sortPropertyDefinition.substring(idx+1).toLowerCase() !== 'desc'; + } else { + sortProperty = sortPropertyDefinition; + asc = true; + } + + sortProperties.push(sortProperty); + sortPropertyAscending[sortProperty] = asc; + changeMeta.property.itemPropertyKey(itemsKey, sortProperty); + }); + + sortPropertyDefinitions.addObserver('@each', this, updateSortPropertiesOnce); + } + + function updateSortPropertiesOnce() { + Ember.run.once(this, updateSortProperties, changeMeta.propertyName); + } + + function updateSortProperties(propertyName) { + setupSortProperties.call(this); + changeMeta.property.recomputeOnce.call(this, propertyName); + } + + Ember.addObserver(this, sortPropertiesKey, updateSortPropertiesOnce); + + setupSortProperties.call(this); + + + instanceMeta.order = function (itemA, itemB) { + var sortProperty, result, asc; + for (var i = 0; i < this.sortProperties.length; ++i) { + sortProperty = this.sortProperties[i]; + result = Ember.compare(get(itemA, sortProperty), get(itemB, sortProperty)); + + if (result !== 0) { + asc = this.sortPropertyAscending[sortProperty]; + return asc ? result : (-1 * result); + } + } + + return 0; + }; + + instanceMeta.binarySearch = binarySearch; + }; + } + + return Ember.arrayComputed.call(null, itemsKey, { + initialize: initFn, + + addedItem: function (array, item, changeMeta, instanceMeta) { + var index = instanceMeta.binarySearch(array, item); + array.insertAt(index, item); + return array; + }, + + removedItem: function (array, item, changeMeta, instanceMeta) { + var proxyProperties, index, searchItem; + + if (changeMeta.previousValues) { + proxyProperties = merge({ content: item }, changeMeta.previousValues); + + searchItem = SearchProxy.create(proxyProperties); + } else { + searchItem = item; + } + + index = instanceMeta.binarySearch(array, searchItem); + array.removeAt(index); + return array; + } + }); +}; + +})(); + + + +(function() { +/** + Expose RSVP implementation + + Documentation can be found here: https://github.com/tildeio/rsvp.js/blob/master/README.md + + @class RSVP + @namespace Ember + @constructor +*/ +Ember.RSVP = requireModule('rsvp'); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-runtime +*/ + +var a_slice = Array.prototype.slice; + +if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Function) { + + /** + The `property` extension of Javascript's Function prototype is available + when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is + `true`, which is the default. + + Computed properties allow you to treat a function like a property: + + ```javascript + MyApp.President = Ember.Object.extend({ + firstName: '', + lastName: '', + + fullName: function() { + return this.get('firstName') + ' ' + this.get('lastName'); + + // Call this flag to mark the function as a property + }.property() + }); + + var president = MyApp.President.create({ + firstName: "Barack", + lastName: "Obama" + }); + + president.get('fullName'); // "Barack Obama" + ``` + + Treating a function like a property is useful because they can work with + bindings, just like any other property. + + Many computed properties have dependencies on other properties. For + example, in the above example, the `fullName` property depends on + `firstName` and `lastName` to determine its value. You can tell Ember + about these dependencies like this: + + ```javascript + MyApp.President = Ember.Object.extend({ + firstName: '', + lastName: '', + + fullName: function() { + return this.get('firstName') + ' ' + this.get('lastName'); + + // Tell Ember.js that this computed property depends on firstName + // and lastName + }.property('firstName', 'lastName') + }); + ``` + + Make sure you list these dependencies so Ember knows when to update + bindings that connect to a computed property. Changing a dependency + will not immediately trigger an update of the computed property, but + will instead clear the cache so that it is updated when the next `get` + is called on the property. + + See [Ember.ComputedProperty](/api/classes/Ember.ComputedProperty.html), [Ember.computed](/api/#method_computed). + + @method property + @for Function + */ + Function.prototype.property = function() { + var ret = Ember.computed(this); + return ret.property.apply(ret, arguments); + }; + + /** + The `observes` extension of Javascript's Function prototype is available + when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is + true, which is the default. + + You can observe property changes simply by adding the `observes` + call to the end of your method declarations in classes that you write. + For example: + + ```javascript + Ember.Object.extend({ + valueObserver: function() { + // Executes whenever the "value" property changes + }.observes('value') + }); + ``` + + In the future this method may become asynchronous. If you want to ensure + synchronous behavior, use `observesImmediately`. + + See `Ember.observer`. + + @method observes + @for Function + */ + Function.prototype.observes = function() { + this.__ember_observes__ = a_slice.call(arguments); + return this; + }; + + /** + The `observesImmediately` extension of Javascript's Function prototype is + available when `Ember.EXTEND_PROTOTYPES` or + `Ember.EXTEND_PROTOTYPES.Function` is true, which is the default. + + You can observe property changes simply by adding the `observesImmediately` + call to the end of your method declarations in classes that you write. + For example: + + ```javascript + Ember.Object.extend({ + valueObserver: function() { + // Executes immediately after the "value" property changes + }.observesImmediately('value') + }); + ``` + + In the future, `observes` may become asynchronous. In this event, + `observesImmediately` will maintain the synchronous behavior. + + See `Ember.immediateObserver`. + + @method observesImmediately + @for Function + */ + Function.prototype.observesImmediately = function() { + for (var i=0, l=arguments.length; i b` + + Default implementation raises an exception. + + @method compare + @param a {Object} the first object to compare + @param b {Object} the second object to compare + @return {Integer} the result of the comparison + */ + compare: Ember.required(Function) + +}); + + +})(); + + + +(function() { +/** +@module ember +@submodule ember-runtime +*/ + + + +var get = Ember.get, set = Ember.set; + +/** + Implements some standard methods for copying an object. Add this mixin to + any object you create that can create a copy of itself. This mixin is + added automatically to the built-in array. + + You should generally implement the `copy()` method to return a copy of the + receiver. + + Note that `frozenCopy()` will only work if you also implement + `Ember.Freezable`. + + @class Copyable + @namespace Ember + @since Ember 0.9 +*/ +Ember.Copyable = Ember.Mixin.create(/** @scope Ember.Copyable.prototype */ { + + /** + Override to return a copy of the receiver. Default implementation raises + an exception. + + @method copy + @param {Boolean} deep if `true`, a deep copy of the object should be made + @return {Object} copy of receiver + */ + copy: Ember.required(Function), + + /** + If the object implements `Ember.Freezable`, then this will return a new + copy if the object is not frozen and the receiver if the object is frozen. + + Raises an exception if you try to call this method on a object that does + not support freezing. + + You should use this method whenever you want a copy of a freezable object + since a freezable object can simply return itself without actually + consuming more memory. + + @method frozenCopy + @return {Object} copy of receiver or receiver + */ + frozenCopy: function() { + if (Ember.Freezable && Ember.Freezable.detect(this)) { + return get(this, 'isFrozen') ? this : this.copy().freeze(); + } else { + throw new Ember.Error(Ember.String.fmt("%@ does not support freezing", [this])); + } + } +}); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-runtime +*/ + + +var get = Ember.get, set = Ember.set; + +/** + The `Ember.Freezable` mixin implements some basic methods for marking an + object as frozen. Once an object is frozen it should be read only. No changes + may be made the internal state of the object. + + ## Enforcement + + To fully support freezing in your subclass, you must include this mixin and + override any method that might alter any property on the object to instead + raise an exception. You can check the state of an object by checking the + `isFrozen` property. + + Although future versions of JavaScript may support language-level freezing + object objects, that is not the case today. Even if an object is freezable, + it is still technically possible to modify the object, even though it could + break other parts of your application that do not expect a frozen object to + change. It is, therefore, very important that you always respect the + `isFrozen` property on all freezable objects. + + ## Example Usage + + The example below shows a simple object that implement the `Ember.Freezable` + protocol. + + ```javascript + Contact = Ember.Object.extend(Ember.Freezable, { + firstName: null, + lastName: null, + + // swaps the names + swapNames: function() { + if (this.get('isFrozen')) throw Ember.FROZEN_ERROR; + var tmp = this.get('firstName'); + this.set('firstName', this.get('lastName')); + this.set('lastName', tmp); + return this; + } + + }); + + c = Contact.create({ firstName: "John", lastName: "Doe" }); + c.swapNames(); // returns c + c.freeze(); + c.swapNames(); // EXCEPTION + ``` + + ## Copying + + Usually the `Ember.Freezable` protocol is implemented in cooperation with the + `Ember.Copyable` protocol, which defines a `frozenCopy()` method that will + return a frozen object, if the object implements this method as well. + + @class Freezable + @namespace Ember + @since Ember 0.9 +*/ +Ember.Freezable = Ember.Mixin.create(/** @scope Ember.Freezable.prototype */ { + + /** + Set to `true` when the object is frozen. Use this property to detect + whether your object is frozen or not. + + @property isFrozen + @type Boolean + */ + isFrozen: false, + + /** + Freezes the object. Once this method has been called the object should + no longer allow any properties to be edited. + + @method freeze + @return {Object} receiver + */ + freeze: function() { + if (get(this, 'isFrozen')) return this; + set(this, 'isFrozen', true); + return this; + } + +}); + +Ember.FROZEN_ERROR = "Frozen object cannot be modified."; + +})(); + + + +(function() { +/** +@module ember +@submodule ember-runtime +*/ + +var forEach = Ember.EnumerableUtils.forEach; + +/** + This mixin defines the API for modifying generic enumerables. These methods + can be applied to an object regardless of whether it is ordered or + unordered. + + Note that an Enumerable can change even if it does not implement this mixin. + For example, a MappedEnumerable cannot be directly modified but if its + underlying enumerable changes, it will change also. + + ## Adding Objects + + To add an object to an enumerable, use the `addObject()` method. This + method will only add the object to the enumerable if the object is not + already present and is of a type supported by the enumerable. + + ```javascript + set.addObject(contact); + ``` + + ## Removing Objects + + To remove an object from an enumerable, use the `removeObject()` method. This + will only remove the object if it is present in the enumerable, otherwise + this method has no effect. + + ```javascript + set.removeObject(contact); + ``` + + ## Implementing In Your Own Code + + If you are implementing an object and want to support this API, just include + this mixin in your class and implement the required methods. In your unit + tests, be sure to apply the Ember.MutableEnumerableTests to your object. + + @class MutableEnumerable + @namespace Ember + @uses Ember.Enumerable +*/ +Ember.MutableEnumerable = Ember.Mixin.create(Ember.Enumerable, { + + /** + __Required.__ You must implement this method to apply this mixin. + + Attempts to add the passed object to the receiver if the object is not + already present in the collection. If the object is present, this method + has no effect. + + If the passed object is of a type not supported by the receiver, + then this method should raise an exception. + + @method addObject + @param {Object} object The object to add to the enumerable. + @return {Object} the passed object + */ + addObject: Ember.required(Function), + + /** + Adds each object in the passed enumerable to the receiver. + + @method addObjects + @param {Ember.Enumerable} objects the objects to add. + @return {Object} receiver + */ + addObjects: function(objects) { + Ember.beginPropertyChanges(this); + forEach(objects, function(obj) { this.addObject(obj); }, this); + Ember.endPropertyChanges(this); + return this; + }, + + /** + __Required.__ You must implement this method to apply this mixin. + + Attempts to remove the passed object from the receiver collection if the + object is present in the collection. If the object is not present, + this method has no effect. + + If the passed object is of a type not supported by the receiver, + then this method should raise an exception. + + @method removeObject + @param {Object} object The object to remove from the enumerable. + @return {Object} the passed object + */ + removeObject: Ember.required(Function), + + + /** + Removes each object in the passed enumerable from the receiver. + + @method removeObjects + @param {Ember.Enumerable} objects the objects to remove + @return {Object} receiver + */ + removeObjects: function(objects) { + Ember.beginPropertyChanges(this); + forEach(objects, function(obj) { this.removeObject(obj); }, this); + Ember.endPropertyChanges(this); + return this; + } + +}); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-runtime +*/ +// .......................................................... +// CONSTANTS +// + +var OUT_OF_RANGE_EXCEPTION = "Index out of range" ; +var EMPTY = []; + +// .......................................................... +// HELPERS +// + +var get = Ember.get, set = Ember.set; + +/** + This mixin defines the API for modifying array-like objects. These methods + can be applied only to a collection that keeps its items in an ordered set. + + Note that an Array can change even if it does not implement this mixin. + For example, one might implement a SparseArray that cannot be directly + modified, but if its underlying enumerable changes, it will change also. + + @class MutableArray + @namespace Ember + @uses Ember.Array + @uses Ember.MutableEnumerable +*/ +Ember.MutableArray = Ember.Mixin.create(Ember.Array, Ember.MutableEnumerable,/** @scope Ember.MutableArray.prototype */ { + + /** + __Required.__ You must implement this method to apply this mixin. + + This is one of the primitives you must implement to support `Ember.Array`. + You should replace amt objects started at idx with the objects in the + passed array. You should also call `this.enumerableContentDidChange()` + + @method replace + @param {Number} idx Starting index in the array to replace. If + idx >= length, then append to the end of the array. + @param {Number} amt Number of elements that should be removed from + the array, starting at *idx*. + @param {Array} objects An array of zero or more objects that should be + inserted into the array at *idx* + */ + replace: Ember.required(), + + /** + Remove all elements from self. This is useful if you + want to reuse an existing array without having to recreate it. + + ```javascript + var colors = ["red", "green", "blue"]; + color.length(); // 3 + colors.clear(); // [] + colors.length(); // 0 + ``` + + @method clear + @return {Ember.Array} An empty Array. + */ + clear: function () { + var len = get(this, 'length'); + if (len === 0) return this; + this.replace(0, len, EMPTY); + return this; + }, + + /** + This will use the primitive `replace()` method to insert an object at the + specified index. + + ```javascript + var colors = ["red", "green", "blue"]; + colors.insertAt(2, "yellow"); // ["red", "green", "yellow", "blue"] + colors.insertAt(5, "orange"); // Error: Index out of range + ``` + + @method insertAt + @param {Number} idx index of insert the object at. + @param {Object} object object to insert + @return this + */ + insertAt: function(idx, object) { + if (idx > get(this, 'length')) throw new Ember.Error(OUT_OF_RANGE_EXCEPTION) ; + this.replace(idx, 0, [object]) ; + return this ; + }, + + /** + Remove an object at the specified index using the `replace()` primitive + method. You can pass either a single index, or a start and a length. + + If you pass a start and length that is beyond the + length this method will throw an `OUT_OF_RANGE_EXCEPTION` + + ```javascript + var colors = ["red", "green", "blue", "yellow", "orange"]; + colors.removeAt(0); // ["green", "blue", "yellow", "orange"] + colors.removeAt(2, 2); // ["green", "blue"] + colors.removeAt(4, 2); // Error: Index out of range + ``` + + @method removeAt + @param {Number} start index, start of range + @param {Number} len length of passing range + @return {Object} receiver + */ + removeAt: function(start, len) { + if ('number' === typeof start) { + + if ((start < 0) || (start >= get(this, 'length'))) { + throw new Ember.Error(OUT_OF_RANGE_EXCEPTION); + } + + // fast case + if (len === undefined) len = 1; + this.replace(start, len, EMPTY); + } + + return this ; + }, + + /** + Push the object onto the end of the array. Works just like `push()` but it + is KVO-compliant. + + ```javascript + var colors = ["red", "green", "blue"]; + colors.pushObject("black"); // ["red", "green", "blue", "black"] + colors.pushObject(["yellow", "orange"]); // ["red", "green", "blue", "black", ["yellow", "orange"]] + ``` + + @method pushObject + @param {*} obj object to push + @return {*} the same obj passed as param + */ + pushObject: function(obj) { + this.insertAt(get(this, 'length'), obj) ; + return obj ; + }, + + /** + Add the objects in the passed numerable to the end of the array. Defers + notifying observers of the change until all objects are added. + + ```javascript + var colors = ["red", "green", "blue"]; + colors.pushObjects(["black"]); // ["red", "green", "blue", "black"] + colors.pushObjects(["yellow", "orange"]); // ["red", "green", "blue", "black", "yellow", "orange"] + ``` + + @method pushObjects + @param {Ember.Enumerable} objects the objects to add + @return {Ember.Array} receiver + */ + pushObjects: function(objects) { + if (!(Ember.Enumerable.detect(objects) || Ember.isArray(objects))) { + throw new TypeError("Must pass Ember.Enumerable to Ember.MutableArray#pushObjects"); + } + this.replace(get(this, 'length'), 0, objects); + return this; + }, + + /** + Pop object from array or nil if none are left. Works just like `pop()` but + it is KVO-compliant. + + ```javascript + var colors = ["red", "green", "blue"]; + colors.popObject(); // "blue" + console.log(colors); // ["red", "green"] + ``` + + @method popObject + @return object + */ + popObject: function() { + var len = get(this, 'length') ; + if (len === 0) return null ; + + var ret = this.objectAt(len-1) ; + this.removeAt(len-1, 1) ; + return ret ; + }, + + /** + Shift an object from start of array or nil if none are left. Works just + like `shift()` but it is KVO-compliant. + + ```javascript + var colors = ["red", "green", "blue"]; + colors.shiftObject(); // "red" + console.log(colors); // ["green", "blue"] + ``` + + @method shiftObject + @return object + */ + shiftObject: function() { + if (get(this, 'length') === 0) return null ; + var ret = this.objectAt(0) ; + this.removeAt(0) ; + return ret ; + }, + + /** + Unshift an object to start of array. Works just like `unshift()` but it is + KVO-compliant. + + ```javascript + var colors = ["red", "green", "blue"]; + colors.unshiftObject("yellow"); // ["yellow", "red", "green", "blue"] + colors.unshiftObject(["black", "white"]); // [["black", "white"], "yellow", "red", "green", "blue"] + ``` + + @method unshiftObject + @param {*} obj object to unshift + @return {*} the same obj passed as param + */ + unshiftObject: function(obj) { + this.insertAt(0, obj) ; + return obj ; + }, + + /** + Adds the named objects to the beginning of the array. Defers notifying + observers until all objects have been added. + + ```javascript + var colors = ["red", "green", "blue"]; + colors.unshiftObjects(["black", "white"]); // ["black", "white", "red", "green", "blue"] + colors.unshiftObjects("yellow"); // Type Error: 'undefined' is not a function + ``` + + @method unshiftObjects + @param {Ember.Enumerable} objects the objects to add + @return {Ember.Array} receiver + */ + unshiftObjects: function(objects) { + this.replace(0, 0, objects); + return this; + }, + + /** + Reverse objects in the array. Works just like `reverse()` but it is + KVO-compliant. + + @method reverseObjects + @return {Ember.Array} receiver + */ + reverseObjects: function() { + var len = get(this, 'length'); + if (len === 0) return this; + var objects = this.toArray().reverse(); + this.replace(0, len, objects); + return this; + }, + + /** + Replace all the the receiver's content with content of the argument. + If argument is an empty array receiver will be cleared. + + ```javascript + var colors = ["red", "green", "blue"]; + colors.setObjects(["black", "white"]); // ["black", "white"] + colors.setObjects([]); // [] + ``` + + @method setObjects + @param {Ember.Array} objects array whose content will be used for replacing + the content of the receiver + @return {Ember.Array} receiver with the new content + */ + setObjects: function(objects) { + if (objects.length === 0) return this.clear(); + + var len = get(this, 'length'); + this.replace(0, len, objects); + return this; + }, + + // .......................................................... + // IMPLEMENT Ember.MutableEnumerable + // + + removeObject: function(obj) { + var loc = get(this, 'length') || 0; + while(--loc >= 0) { + var curObject = this.objectAt(loc) ; + if (curObject === obj) this.removeAt(loc) ; + } + return this ; + }, + + addObject: function(obj) { + if (!this.contains(obj)) this.pushObject(obj); + return this ; + } + +}); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-runtime +*/ + +var get = Ember.get, set = Ember.set; + +/** +`Ember.TargetActionSupport` is a mixin that can be included in a class +to add a `triggerAction` method with semantics similar to the Handlebars +`{{action}}` helper. In normal Ember usage, the `{{action}}` helper is +usually the best choice. This mixin is most often useful when you are +doing more complex event handling in View objects. + +See also `Ember.ViewTargetActionSupport`, which has +view-aware defaults for target and actionContext. + +@class TargetActionSupport +@namespace Ember +@extends Ember.Mixin +*/ +Ember.TargetActionSupport = Ember.Mixin.create({ + target: null, + action: null, + actionContext: null, + + targetObject: Ember.computed(function() { + var target = get(this, 'target'); + + if (Ember.typeOf(target) === "string") { + var value = get(this, target); + if (value === undefined) { value = get(Ember.lookup, target); } + return value; + } else { + return target; + } + }).property('target'), + + actionContextObject: Ember.computed(function() { + var actionContext = get(this, 'actionContext'); + + if (Ember.typeOf(actionContext) === "string") { + var value = get(this, actionContext); + if (value === undefined) { value = get(Ember.lookup, actionContext); } + return value; + } else { + return actionContext; + } + }).property('actionContext'), + + /** + Send an "action" with an "actionContext" to a "target". The action, actionContext + and target will be retrieved from properties of the object. For example: + + ```javascript + App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, { + target: Ember.computed.alias('controller'), + action: 'save', + actionContext: Ember.computed.alias('context'), + click: function() { + this.triggerAction(); // Sends the `save` action, along with the current context + // to the current controller + } + }); + ``` + + The `target`, `action`, and `actionContext` can be provided as properties of + an optional object argument to `triggerAction` as well. + + ```javascript + App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, { + click: function() { + this.triggerAction({ + action: 'save', + target: this.get('controller'), + actionContext: this.get('context'), + }); // Sends the `save` action, along with the current context + // to the current controller + } + }); + ``` + + The `actionContext` defaults to the object you mixing `TargetActionSupport` into. + But `target` and `action` must be specified either as properties or with the argument + to `triggerAction`, or a combination: + + ```javascript + App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, { + target: Ember.computed.alias('controller'), + click: function() { + this.triggerAction({ + action: 'save' + }); // Sends the `save` action, along with a reference to `this`, + // to the current controller + } + }); + ``` + + @method triggerAction + @param opts {Hash} (optional, with the optional keys action, target and/or actionContext) + @return {Boolean} true if the action was sent successfully and did not return false + */ + triggerAction: function(opts) { + opts = opts || {}; + var action = opts.action || get(this, 'action'), + target = opts.target || get(this, 'targetObject'), + actionContext = opts.actionContext; + + function args(options, actionName) { + var ret = []; + if (actionName) { ret.push(actionName); } + + return ret.concat(options); + } + + if (typeof actionContext === 'undefined') { + actionContext = get(this, 'actionContextObject') || this; + } + + if (target && action) { + var ret; + + if (target.send) { + ret = target.send.apply(target, args(actionContext, action)); + } else { + Ember.assert("The action '" + action + "' did not exist on " + target, typeof target[action] === 'function'); + ret = target[action].apply(target, args(actionContext)); + } + + if (ret !== false) ret = true; + + return ret; + } else { + return false; + } + } +}); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-runtime +*/ + +/** + This mixin allows for Ember objects to subscribe to and emit events. + + ```javascript + App.Person = Ember.Object.extend(Ember.Evented, { + greet: function() { + // ... + this.trigger('greet'); + } + }); + + var person = App.Person.create(); + + person.on('greet', function() { + console.log('Our person has greeted'); + }); + + person.greet(); + + // outputs: 'Our person has greeted' + ``` + + You can also chain multiple event subscriptions: + + ```javascript + person.on('greet', function() { + console.log('Our person has greeted'); + }).one('greet', function() { + console.log('Offer one-time special'); + }).off('event', this, forgetThis); + ``` + + @class Evented + @namespace Ember + */ +Ember.Evented = Ember.Mixin.create({ + + /** + Subscribes to a named event with given function. + + ```javascript + person.on('didLoad', function() { + // fired once the person has loaded + }); + ``` + + An optional target can be passed in as the 2nd argument that will + be set as the "this" for the callback. This is a good way to give your + function access to the object triggering the event. When the target + parameter is used the callback becomes the third argument. + + @method on + @param {String} name The name of the event + @param {Object} [target] The "this" binding for the callback + @param {Function} method The callback to execute + @return this + */ + on: function(name, target, method) { + Ember.addListener(this, name, target, method); + return this; + }, + + /** + Subscribes a function to a named event and then cancels the subscription + after the first time the event is triggered. It is good to use ``one`` when + you only care about the first time an event has taken place. + + This function takes an optional 2nd argument that will become the "this" + value for the callback. If this argument is passed then the 3rd argument + becomes the function. + + @method one + @param {String} name The name of the event + @param {Object} [target] The "this" binding for the callback + @param {Function} method The callback to execute + @return this + */ + one: function(name, target, method) { + if (!method) { + method = target; + target = null; + } + + Ember.addListener(this, name, target, method, true); + return this; + }, + + /** + Triggers a named event for the object. Any additional arguments + will be passed as parameters to the functions that are subscribed to the + event. + + ```javascript + person.on('didEat', function(food) { + console.log('person ate some ' + food); + }); + + person.trigger('didEat', 'broccoli'); + + // outputs: person ate some broccoli + ``` + @method trigger + @param {String} name The name of the event + @param {Object...} args Optional arguments to pass on + */ + trigger: function(name) { + var args = [], i, l; + for (i = 1, l = arguments.length; i < l; i++) { + args.push(arguments[i]); + } + Ember.sendEvent(this, name, args); + }, + + /** + Cancels subscription for given name, target, and method. + + @method off + @param {String} name The name of the event + @param {Object} target The target of the subscription + @param {Function} method The function of the subscription + @return this + */ + off: function(name, target, method) { + Ember.removeListener(this, name, target, method); + return this; + }, + + /** + Checks to see if object has any subscriptions for named event. + + @method has + @param {String} name The name of the event + @return {Boolean} does the object have a subscription for event + */ + has: function(name) { + return Ember.hasListeners(this, name); + } +}); + +})(); + + + +(function() { +var RSVP = requireModule("rsvp"); + +RSVP.configure('async', function(callback, promise) { + Ember.run.schedule('actions', promise, callback, promise); +}); + +/** +@module ember +@submodule ember-runtime +*/ + +var get = Ember.get; + +/** + @class Deferred + @namespace Ember + */ +Ember.DeferredMixin = Ember.Mixin.create({ + /** + Add handlers to be called when the Deferred object is resolved or rejected. + + @method then + @param {Function} resolve a callback function to be called when done + @param {Function} reject a callback function to be called when failed + */ + then: function(resolve, reject) { + var deferred, promise, entity; + + entity = this; + deferred = get(this, '_deferred'); + promise = deferred.promise; + + function fulfillmentHandler(fulfillment) { + if (fulfillment === promise) { + return resolve(entity); + } else { + return resolve(fulfillment); + } + } + + return promise.then(resolve && fulfillmentHandler, reject); + }, + + /** + Resolve a Deferred object and call any `doneCallbacks` with the given args. + + @method resolve + */ + resolve: function(value) { + var deferred, promise; + + deferred = get(this, '_deferred'); + promise = deferred.promise; + + if (value === this) { + deferred.resolve(promise); + } else { + deferred.resolve(value); + } + }, + + /** + Reject a Deferred object and call any `failCallbacks` with the given args. + + @method reject + */ + reject: function(value) { + get(this, '_deferred').reject(value); + }, + + _deferred: Ember.computed(function() { + return RSVP.defer(); + }) +}); + + +})(); + + + +(function() { +/** +@module ember +@submodule ember-runtime +*/ + +var get = Ember.get, typeOf = Ember.typeOf; + +/** + The `Ember.ActionHandler` mixin implements support for moving an `actions` + property to an `_actions` property at extend time, and adding `_actions` + to the object's mergedProperties list. + + `Ember.ActionHandler` is used internally by Ember in `Ember.View`, + `Ember.Controller`, and `Ember.Route`. + + @class ActionHandler + @namespace Ember +*/ +Ember.ActionHandler = Ember.Mixin.create({ + mergedProperties: ['_actions'], + + /** + @private + + Moves `actions` to `_actions` at extend time. Note that this currently + modifies the mixin themselves, which is technically dubious but + is practically of little consequence. This may change in the future. + + @method willMergeMixin + */ + willMergeMixin: function(props) { + var hashName; + + if (!props._actions) { + if (typeOf(props.actions) === 'object') { + hashName = 'actions'; + } else if (typeOf(props.events) === 'object') { + Ember.deprecate('Action handlers contained in an `events` object are deprecated in favor of putting them in an `actions` object', false); + hashName = 'events'; + } + + if (hashName) { + props._actions = Ember.merge(props._actions || {}, props[hashName]); + } + + delete props[hashName]; + } + }, + + send: function(actionName) { + var args = [].slice.call(arguments, 1), target; + + if (this._actions && this._actions[actionName]) { + if (this._actions[actionName].apply(this, args) === true) { + // handler returned true, so this action will bubble + } else { + return; + } + } else if (this.deprecatedSend && this.deprecatedSendHandles && this.deprecatedSendHandles(actionName)) { + if (this.deprecatedSend.apply(this, [].slice.call(arguments)) === true) { + // handler return true, so this action will bubble + } else { + return; + } + } + + if (target = get(this, 'target')) { + Ember.assert("The `target` for " + this + " (" + target + ") does not have a `send` method", typeof target.send === 'function'); + target.send.apply(target, arguments); + } + } + +}); + +})(); + + + +(function() { +var set = Ember.set, get = Ember.get, + resolve = Ember.RSVP.resolve, + rethrow = Ember.RSVP.rethrow, + not = Ember.computed.not, + or = Ember.computed.or; + +/** + @module ember + @submodule ember-runtime + */ + +function observePromise(proxy, promise) { + promise.then(function(value) { + set(proxy, 'isFulfilled', true); + set(proxy, 'content', value); + }, function(reason) { + set(proxy, 'isRejected', true); + set(proxy, 'reason', reason); + // don't re-throw, as we are merely observing + }); +} + +/** + A low level mixin making ObjectProxy, ObjectController or ArrayController's promise aware. + + ```javascript + var ObjectPromiseController = Ember.ObjectController.extend(Ember.PromiseProxyMixin); + + var controller = ObjectPromiseController.create({ + promise: $.getJSON('/some/remote/data.json') + }); + + controller.then(function(json){ + // the json + }, function(reason) { + // the reason why you have no json + }); + ``` + + the controller has bindable attributes which + track the promises life cycle + + ```javascript + controller.get('isPending') //=> true + controller.get('isSettled') //=> false + controller.get('isRejected') //=> false + controller.get('isFulfilled') //=> false + ``` + + When the the $.getJSON completes, and the promise is fulfilled + with json, the life cycle attributes will update accordingly. + + ```javascript + controller.get('isPending') //=> false + controller.get('isSettled') //=> true + controller.get('isRejected') //=> false + controller.get('isFulfilled') //=> true + ``` + + As the controller is an ObjectController, and the json now its content, + all the json properties will be available directly from the controller. + + ```javascript + // Assuming the following json: + { + firstName: 'Stefan', + lastName: 'Penner' + } + + // both properties will accessible on the controller + controller.get('firstName') //=> 'Stefan' + controller.get('lastName') //=> 'Penner' + ``` + + If the controller is backing a template, the attributes are + bindable from within that template + + ```handlebars + {{#if isPending}} + loading... + {{else}} + firstName: {{firstName}} + lastName: {{lastName}} + {{/if}} + ``` + @class Ember.PromiseProxyMixin +*/ +Ember.PromiseProxyMixin = Ember.Mixin.create({ + reason: null, + isPending: not('isSettled').readOnly(), + isSettled: or('isRejected', 'isFulfilled').readOnly(), + isRejected: false, + isFulfilled: false, + + promise: Ember.computed(function(key, promise) { + if (arguments.length === 2) { + promise = resolve(promise); + observePromise(this, promise); + return promise.then(); // fork the promise. + } else { + throw new Ember.Error("PromiseProxy's promise must be set"); + } + }), + + then: function(fulfill, reject) { + return get(this, 'promise').then(fulfill, reject); + } +}); + + + +})(); + + + +(function() { + +})(); + + + +(function() { +var get = Ember.get, + forEach = Ember.EnumerableUtils.forEach, + RETAIN = 'r', + INSERT = 'i', + DELETE = 'd'; + +/** + An `Ember.TrackedArray` tracks array operations. It's useful when you want to + lazily compute the indexes of items in an array after they've been shifted by + subsequent operations. + + @class TrackedArray + @namespace Ember + @param {array} [items=[]] The array to be tracked. This is used just to get + the initial items for the starting state of retain:n. +*/ +Ember.TrackedArray = function (items) { + if (arguments.length < 1) { items = []; } + + var length = get(items, 'length'); + + if (length) { + this._operations = [new ArrayOperation(RETAIN, length, items)]; + } else { + this._operations = []; + } +}; + +Ember.TrackedArray.RETAIN = RETAIN; +Ember.TrackedArray.INSERT = INSERT; +Ember.TrackedArray.DELETE = DELETE; + +Ember.TrackedArray.prototype = { + + /** + Track that `newItems` were added to the tracked array at `index`. + + @method addItems + @param index + @param newItems + */ + addItems: function (index, newItems) { + var count = get(newItems, 'length'); + if (count < 1) { return; } + + var match = this._findArrayOperation(index), + arrayOperation = match.operation, + arrayOperationIndex = match.index, + arrayOperationRangeStart = match.rangeStart, + composeIndex, + splitIndex, + splitItems, + splitArrayOperation, + newArrayOperation; + + newArrayOperation = new ArrayOperation(INSERT, count, newItems); + + if (arrayOperation) { + if (!match.split) { + // insert left of arrayOperation + this._operations.splice(arrayOperationIndex, 0, newArrayOperation); + composeIndex = arrayOperationIndex; + } else { + this._split(arrayOperationIndex, index - arrayOperationRangeStart, newArrayOperation); + composeIndex = arrayOperationIndex + 1; + } + } else { + // insert at end + this._operations.push(newArrayOperation); + composeIndex = arrayOperationIndex; + } + + this._composeInsert(composeIndex); + }, + + /** + Track that `count` items were removed at `index`. + + @method removeItems + @param index + @param count + */ + removeItems: function (index, count) { + if (count < 1) { return; } + + var match = this._findArrayOperation(index), + arrayOperation = match.operation, + arrayOperationIndex = match.index, + arrayOperationRangeStart = match.rangeStart, + newArrayOperation, + composeIndex; + + newArrayOperation = new ArrayOperation(DELETE, count); + if (!match.split) { + // insert left of arrayOperation + this._operations.splice(arrayOperationIndex, 0, newArrayOperation); + composeIndex = arrayOperationIndex; + } else { + this._split(arrayOperationIndex, index - arrayOperationRangeStart, newArrayOperation); + composeIndex = arrayOperationIndex + 1; + } + + return this._composeDelete(composeIndex); + }, + + /** + Apply all operations, reducing them to retain:n, for `n`, the number of + items in the array. + + `callback` will be called for each operation and will be passed the following arguments: + * {array} items The items for the given operation + * {number} offset The computed offset of the items, ie the index in the + array of the first item for this operation. + * {string} operation The type of the operation. One of + `Ember.TrackedArray.{RETAIN, DELETE, INSERT}` + + @method apply + @param {function} callback + */ + apply: function (callback) { + var items = [], + offset = 0; + + forEach(this._operations, function (arrayOperation) { + callback(arrayOperation.items, offset, arrayOperation.type); + + if (arrayOperation.type !== DELETE) { + offset += arrayOperation.count; + items = items.concat(arrayOperation.items); + } + }); + + this._operations = [new ArrayOperation(RETAIN, items.length, items)]; + }, + + /** + Return an ArrayOperationMatch for the operation that contains the item at `index`. + + @method _findArrayOperation + + @param {number} index the index of the item whose operation information + should be returned. + @private + */ + _findArrayOperation: function (index) { + var arrayOperationIndex, + len, + split = false, + arrayOperation, + arrayOperationRangeStart, + arrayOperationRangeEnd; + + // OPTIMIZE: we could search these faster if we kept a balanced tree. + // find leftmost arrayOperation to the right of `index` + for (arrayOperationIndex = arrayOperationRangeStart = 0, len = this._operations.length; arrayOperationIndex < len; ++arrayOperationIndex) { + arrayOperation = this._operations[arrayOperationIndex]; + + if (arrayOperation.type === DELETE) { continue; } + + arrayOperationRangeEnd = arrayOperationRangeStart + arrayOperation.count - 1; + + if (index === arrayOperationRangeStart) { + break; + } else if (index > arrayOperationRangeStart && index <= arrayOperationRangeEnd) { + split = true; + break; + } else { + arrayOperationRangeStart = arrayOperationRangeEnd + 1; + } + } + + return new ArrayOperationMatch(arrayOperation, arrayOperationIndex, split, arrayOperationRangeStart); + }, + + _split: function (arrayOperationIndex, splitIndex, newArrayOperation) { + var arrayOperation = this._operations[arrayOperationIndex], + splitItems = arrayOperation.items.slice(splitIndex), + splitArrayOperation = new ArrayOperation(arrayOperation.type, splitItems.length, splitItems); + + // truncate LHS + arrayOperation.count = splitIndex; + arrayOperation.items = arrayOperation.items.slice(0, splitIndex); + + this._operations.splice(arrayOperationIndex + 1, 0, newArrayOperation, splitArrayOperation); + }, + + // see SubArray for a better implementation. + _composeInsert: function (index) { + var newArrayOperation = this._operations[index], + leftArrayOperation = this._operations[index-1], // may be undefined + rightArrayOperation = this._operations[index+1], // may be undefined + leftOp = leftArrayOperation && leftArrayOperation.type, + rightOp = rightArrayOperation && rightArrayOperation.type; + + if (leftOp === INSERT) { + // merge left + leftArrayOperation.count += newArrayOperation.count; + leftArrayOperation.items = leftArrayOperation.items.concat(newArrayOperation.items); + + if (rightOp === INSERT) { + // also merge right (we have split an insert with an insert) + leftArrayOperation.count += rightArrayOperation.count; + leftArrayOperation.items = leftArrayOperation.items.concat(rightArrayOperation.items); + this._operations.splice(index, 2); + } else { + // only merge left + this._operations.splice(index, 1); + } + } else if (rightOp === INSERT) { + // merge right + newArrayOperation.count += rightArrayOperation.count; + newArrayOperation.items = newArrayOperation.items.concat(rightArrayOperation.items); + this._operations.splice(index + 1, 1); + } + }, + + _composeDelete: function (index) { + var arrayOperation = this._operations[index], + deletesToGo = arrayOperation.count, + leftArrayOperation = this._operations[index-1], // may be undefined + leftOp = leftArrayOperation && leftArrayOperation.type, + nextArrayOperation, + nextOp, + nextCount, + removeNewAndNextOp = false, + removedItems = []; + + if (leftOp === DELETE) { + arrayOperation = leftArrayOperation; + index -= 1; + } + + for (var i = index + 1; deletesToGo > 0; ++i) { + nextArrayOperation = this._operations[i]; + nextOp = nextArrayOperation.type; + nextCount = nextArrayOperation.count; + + if (nextOp === DELETE) { + arrayOperation.count += nextCount; + continue; + } + + if (nextCount > deletesToGo) { + // d:2 {r,i}:5 we reduce the retain or insert, but it stays + removedItems = removedItems.concat(nextArrayOperation.items.splice(0, deletesToGo)); + nextArrayOperation.count -= deletesToGo; + + // In the case where we truncate the last arrayOperation, we don't need to + // remove it; also the deletesToGo reduction is not the entirety of + // nextCount + i -= 1; + nextCount = deletesToGo; + + deletesToGo = 0; + } else { + if (nextCount === deletesToGo) { + // Handle edge case of d:2 i:2 in which case both operations go away + // during composition. + removeNewAndNextOp = true; + } + removedItems = removedItems.concat(nextArrayOperation.items); + deletesToGo -= nextCount; + } + + if (nextOp === INSERT) { + // d:2 i:3 will result in delete going away + arrayOperation.count -= nextCount; + } + } + + if (arrayOperation.count > 0) { + // compose our new delete with possibly several operations to the right of + // disparate types + this._operations.splice(index+1, i-1-index); + } else { + // The delete operation can go away; it has merely reduced some other + // operation, as in d:3 i:4; it may also have eliminated that operation, + // as in d:3 i:3. + this._operations.splice(index, removeNewAndNextOp ? 2 : 1); + } + + return removedItems; + }, + + toString: function () { + var str = ""; + forEach(this._operations, function (operation) { + str += " " + operation.type + ":" + operation.count; + }); + return str.substring(1); + } +}; + +/** + Internal data structure to represent an array operation. + + @method ArrayOperation + @private + @property {string} type The type of the operation. One of + `Ember.TrackedArray.{RETAIN, INSERT, DELETE}` + @property {number} count The number of items in this operation. + @property {array} items The items of the operation, if included. RETAIN and + INSERT include their items, DELETE does not. +*/ +function ArrayOperation (operation, count, items) { + this.type = operation; // RETAIN | INSERT | DELETE + this.count = count; + this.items = items; +} + +/** + Internal data structure used to include information when looking up operations + by item index. + + @method ArrayOperationMatch + @private + @property {ArrayOperation} operation + @property {number} index The index of `operation` in the array of operations. + @property {boolean} split Whether or not the item index searched for would + require a split for a new operation type. + @property {number} rangeStart The index of the first item in the operation, + with respect to the tracked array. The index of the last item can be computed + from `rangeStart` and `operation.count`. +*/ +function ArrayOperationMatch(operation, index, split, rangeStart) { + this.operation = operation; + this.index = index; + this.split = split; + this.rangeStart = rangeStart; +} + +})(); + + + +(function() { +var get = Ember.get, + forEach = Ember.EnumerableUtils.forEach, + RETAIN = 'r', + FILTER = 'f'; + +function Operation (type, count) { + this.type = type; + this.count = count; +} + +/** + An `Ember.SubArray` tracks an array in a way similar to, but more specialized + than, `Ember.TrackedArray`. It is useful for keeping track of the indexes of + items within a filtered array. + + @class SubArray + @namespace Ember +*/ +Ember.SubArray = function (length) { + if (arguments.length < 1) { length = 0; } + + if (length > 0) { + this._operations = [new Operation(RETAIN, length)]; + } else { + this._operations = []; + } +}; + +Ember.SubArray.prototype = { + /** + Track that an item was added to the tracked array. + + @method addItem + + @param {number} index The index of the item in the tracked array. + @param {boolean} match `true` iff the item is included in the subarray. + + @return {number} The index of the item in the subarray. + */ + addItem: function(index, match) { + var returnValue = -1, + itemType = match ? RETAIN : FILTER, + self = this; + + this._findOperation(index, function(operation, operationIndex, rangeStart, rangeEnd, seenInSubArray) { + var newOperation, splitOperation; + + if (itemType === operation.type) { + ++operation.count; + } else if (index === rangeStart) { + // insert to the left of `operation` + self._operations.splice(operationIndex, 0, new Operation(itemType, 1)); + } else { + newOperation = new Operation(itemType, 1); + splitOperation = new Operation(operation.type, rangeEnd - index + 1); + operation.count = index - rangeStart; + + self._operations.splice(operationIndex + 1, 0, newOperation, splitOperation); + } + + if (match) { + if (operation.type === RETAIN) { + returnValue = seenInSubArray + (index - rangeStart); + } else { + returnValue = seenInSubArray; + } + } + + self._composeAt(operationIndex); + }, function(seenInSubArray) { + self._operations.push(new Operation(itemType, 1)); + + if (match) { + returnValue = seenInSubArray; + } + + self._composeAt(self._operations.length-1); + }); + + return returnValue; + }, + + /** + Track that an item was removed from the tracked array. + + @method removeItem + + @param {number} index The index of the item in the tracked array. + + @return {number} The index of the item in the subarray, or `-1` if the item + was not in the subarray. + */ + removeItem: function(index) { + var returnValue = -1, + self = this; + + this._findOperation(index, function (operation, operationIndex, rangeStart, rangeEnd, seenInSubArray) { + if (operation.type === RETAIN) { + returnValue = seenInSubArray + (index - rangeStart); + } + + if (operation.count > 1) { + --operation.count; + } else { + self._operations.splice(operationIndex, 1); + self._composeAt(operationIndex); + } + }, function() { + throw new Ember.Error("Can't remove an item that has never been added."); + }); + + return returnValue; + }, + + + _findOperation: function (index, foundCallback, notFoundCallback) { + var operationIndex, + len, + operation, + rangeStart, + rangeEnd, + seenInSubArray = 0; + + // OPTIMIZE: change to balanced tree + // find leftmost operation to the right of `index` + for (operationIndex = rangeStart = 0, len = this._operations.length; operationIndex < len; rangeStart = rangeEnd + 1, ++operationIndex) { + operation = this._operations[operationIndex]; + rangeEnd = rangeStart + operation.count - 1; + + if (index >= rangeStart && index <= rangeEnd) { + foundCallback(operation, operationIndex, rangeStart, rangeEnd, seenInSubArray); + return; + } else if (operation.type === RETAIN) { + seenInSubArray += operation.count; + } + } + + notFoundCallback(seenInSubArray); + }, + + _composeAt: function(index) { + var op = this._operations[index], + otherOp; + + if (!op) { + // Composing out of bounds is a no-op, as when removing the last operation + // in the list. + return; + } + + if (index > 0) { + otherOp = this._operations[index-1]; + if (otherOp.type === op.type) { + op.count += otherOp.count; + this._operations.splice(index-1, 1); + --index; + } + } + + if (index < this._operations.length-1) { + otherOp = this._operations[index+1]; + if (otherOp.type === op.type) { + op.count += otherOp.count; + this._operations.splice(index+1, 1); + } + } + }, + + toString: function () { + var str = ""; + forEach(this._operations, function (operation) { + str += " " + operation.type + ":" + operation.count; + }); + return str.substring(1); + } +}; + +})(); + + + +(function() { +Ember.Container = requireModule('container'); +Ember.Container.set = Ember.set; + +})(); + + + +(function() { +Ember.Application = Ember.Namespace.extend(); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-runtime +*/ + +var OUT_OF_RANGE_EXCEPTION = "Index out of range"; +var EMPTY = []; + +var get = Ember.get, set = Ember.set; + +/** + An ArrayProxy wraps any other object that implements `Ember.Array` and/or + `Ember.MutableArray,` forwarding all requests. This makes it very useful for + a number of binding use cases or other cases where being able to swap + out the underlying array is useful. + + A simple example of usage: + + ```javascript + var pets = ['dog', 'cat', 'fish']; + var ap = Ember.ArrayProxy.create({ content: Ember.A(pets) }); + + ap.get('firstObject'); // 'dog' + ap.set('content', ['amoeba', 'paramecium']); + ap.get('firstObject'); // 'amoeba' + ``` + + This class can also be useful as a layer to transform the contents of + an array, as they are accessed. This can be done by overriding + `objectAtContent`: + + ```javascript + var pets = ['dog', 'cat', 'fish']; + var ap = Ember.ArrayProxy.create({ + content: Ember.A(pets), + objectAtContent: function(idx) { + return this.get('content').objectAt(idx).toUpperCase(); + } + }); + + ap.get('firstObject'); // . 'DOG' + ``` + + @class ArrayProxy + @namespace Ember + @extends Ember.Object + @uses Ember.MutableArray +*/ +Ember.ArrayProxy = Ember.Object.extend(Ember.MutableArray,/** @scope Ember.ArrayProxy.prototype */ { + + /** + The content array. Must be an object that implements `Ember.Array` and/or + `Ember.MutableArray.` + + @property content + @type Ember.Array + */ + content: null, + + /** + The array that the proxy pretends to be. In the default `ArrayProxy` + implementation, this and `content` are the same. Subclasses of `ArrayProxy` + can override this property to provide things like sorting and filtering. + + @property arrangedContent + */ + arrangedContent: Ember.computed.alias('content'), + + /** + Should actually retrieve the object at the specified index from the + content. You can override this method in subclasses to transform the + content item to something new. + + This method will only be called if content is non-`null`. + + @method objectAtContent + @param {Number} idx The index to retrieve. + @return {Object} the value or undefined if none found + */ + objectAtContent: function(idx) { + return get(this, 'arrangedContent').objectAt(idx); + }, + + /** + Should actually replace the specified objects on the content array. + You can override this method in subclasses to transform the content item + into something new. + + This method will only be called if content is non-`null`. + + @method replaceContent + @param {Number} idx The starting index + @param {Number} amt The number of items to remove from the content. + @param {Array} objects Optional array of objects to insert or null if no + objects. + @return {void} + */ + replaceContent: function(idx, amt, objects) { + get(this, 'content').replace(idx, amt, objects); + }, + + /** + @private + + Invoked when the content property is about to change. Notifies observers that the + entire array content will change. + + @method _contentWillChange + */ + _contentWillChange: Ember.beforeObserver('content', function() { + this._teardownContent(); + }), + + _teardownContent: function() { + var content = get(this, 'content'); + + if (content) { + content.removeArrayObserver(this, { + willChange: 'contentArrayWillChange', + didChange: 'contentArrayDidChange' + }); + } + }, + + contentArrayWillChange: Ember.K, + contentArrayDidChange: Ember.K, + + /** + @private + + Invoked when the content property changes. Notifies observers that the + entire array content has changed. + + @method _contentDidChange + */ + _contentDidChange: Ember.observer('content', function() { + var content = get(this, 'content'); + + Ember.assert("Can't set ArrayProxy's content to itself", content !== this); + + this._setupContent(); + }), + + _setupContent: function() { + var content = get(this, 'content'); + + if (content) { + content.addArrayObserver(this, { + willChange: 'contentArrayWillChange', + didChange: 'contentArrayDidChange' + }); + } + }, + + _arrangedContentWillChange: Ember.beforeObserver('arrangedContent', function() { + var arrangedContent = get(this, 'arrangedContent'), + len = arrangedContent ? get(arrangedContent, 'length') : 0; + + this.arrangedContentArrayWillChange(this, 0, len, undefined); + this.arrangedContentWillChange(this); + + this._teardownArrangedContent(arrangedContent); + }), + + _arrangedContentDidChange: Ember.observer('arrangedContent', function() { + var arrangedContent = get(this, 'arrangedContent'), + len = arrangedContent ? get(arrangedContent, 'length') : 0; + + Ember.assert("Can't set ArrayProxy's content to itself", arrangedContent !== this); + + this._setupArrangedContent(); + + this.arrangedContentDidChange(this); + this.arrangedContentArrayDidChange(this, 0, undefined, len); + }), + + _setupArrangedContent: function() { + var arrangedContent = get(this, 'arrangedContent'); + + if (arrangedContent) { + arrangedContent.addArrayObserver(this, { + willChange: 'arrangedContentArrayWillChange', + didChange: 'arrangedContentArrayDidChange' + }); + } + }, + + _teardownArrangedContent: function() { + var arrangedContent = get(this, 'arrangedContent'); + + if (arrangedContent) { + arrangedContent.removeArrayObserver(this, { + willChange: 'arrangedContentArrayWillChange', + didChange: 'arrangedContentArrayDidChange' + }); + } + }, + + arrangedContentWillChange: Ember.K, + arrangedContentDidChange: Ember.K, + + objectAt: function(idx) { + return get(this, 'content') && this.objectAtContent(idx); + }, + + length: Ember.computed(function() { + var arrangedContent = get(this, 'arrangedContent'); + return arrangedContent ? get(arrangedContent, 'length') : 0; + // No dependencies since Enumerable notifies length of change + }), + + _replace: function(idx, amt, objects) { + var content = get(this, 'content'); + Ember.assert('The content property of '+ this.constructor + ' should be set before modifying it', content); + if (content) this.replaceContent(idx, amt, objects); + return this; + }, + + replace: function() { + if (get(this, 'arrangedContent') === get(this, 'content')) { + this._replace.apply(this, arguments); + } else { + throw new Ember.Error("Using replace on an arranged ArrayProxy is not allowed."); + } + }, + + _insertAt: function(idx, object) { + if (idx > get(this, 'content.length')) throw new Ember.Error(OUT_OF_RANGE_EXCEPTION); + this._replace(idx, 0, [object]); + return this; + }, + + insertAt: function(idx, object) { + if (get(this, 'arrangedContent') === get(this, 'content')) { + return this._insertAt(idx, object); + } else { + throw new Ember.Error("Using insertAt on an arranged ArrayProxy is not allowed."); + } + }, + + removeAt: function(start, len) { + if ('number' === typeof start) { + var content = get(this, 'content'), + arrangedContent = get(this, 'arrangedContent'), + indices = [], i; + + if ((start < 0) || (start >= get(this, 'length'))) { + throw new Ember.Error(OUT_OF_RANGE_EXCEPTION); + } + + if (len === undefined) len = 1; + + // Get a list of indices in original content to remove + for (i=start; i=idx) { + var item = content.objectAt(loc); + if (item) { + Ember.assert('When using @each to observe the array ' + content + ', the array must return an object', Ember.typeOf(item) === 'instance' || Ember.typeOf(item) === 'object'); + Ember.addBeforeObserver(item, keyName, proxy, 'contentKeyWillChange'); + Ember.addObserver(item, keyName, proxy, 'contentKeyDidChange'); + + // keep track of the index each item was found at so we can map + // it back when the obj changes. + guid = guidFor(item); + if (!objects[guid]) objects[guid] = []; + objects[guid].push(loc); + } + } +} + +function removeObserverForContentKey(content, keyName, proxy, idx, loc) { + var objects = proxy._objects; + if (!objects) objects = proxy._objects = {}; + var indicies, guid; + + while(--loc>=idx) { + var item = content.objectAt(loc); + if (item) { + Ember.removeBeforeObserver(item, keyName, proxy, 'contentKeyWillChange'); + Ember.removeObserver(item, keyName, proxy, 'contentKeyDidChange'); + + guid = guidFor(item); + indicies = objects[guid]; + indicies[indexOf.call(indicies, loc)] = null; + } + } +} + +/** + This is the object instance returned when you get the `@each` property on an + array. It uses the unknownProperty handler to automatically create + EachArray instances for property names. + + @private + @class EachProxy + @namespace Ember + @extends Ember.Object +*/ +Ember.EachProxy = Ember.Object.extend({ + + init: function(content) { + this._super(); + this._content = content; + content.addArrayObserver(this); + + // in case someone is already observing some keys make sure they are + // added + forEach(Ember.watchedEvents(this), function(eventName) { + this.didAddListener(eventName); + }, this); + }, + + /** + You can directly access mapped properties by simply requesting them. + The `unknownProperty` handler will generate an EachArray of each item. + + @method unknownProperty + @param keyName {String} + @param value {*} + */ + unknownProperty: function(keyName, value) { + var ret; + ret = new EachArray(this._content, keyName, this); + Ember.defineProperty(this, keyName, null, ret); + this.beginObservingContentKey(keyName); + return ret; + }, + + // .......................................................... + // ARRAY CHANGES + // Invokes whenever the content array itself changes. + + arrayWillChange: function(content, idx, removedCnt, addedCnt) { + var keys = this._keys, key, lim; + + lim = removedCnt>0 ? idx+removedCnt : -1; + Ember.beginPropertyChanges(this); + + for(key in keys) { + if (!keys.hasOwnProperty(key)) { continue; } + + if (lim>0) { removeObserverForContentKey(content, key, this, idx, lim); } + + Ember.propertyWillChange(this, key); + } + + Ember.propertyWillChange(this._content, '@each'); + Ember.endPropertyChanges(this); + }, + + arrayDidChange: function(content, idx, removedCnt, addedCnt) { + var keys = this._keys, lim; + + lim = addedCnt>0 ? idx+addedCnt : -1; + Ember.changeProperties(function() { + for(var key in keys) { + if (!keys.hasOwnProperty(key)) { continue; } + + if (lim>0) { addObserverForContentKey(content, key, this, idx, lim); } + + Ember.propertyDidChange(this, key); + } + + Ember.propertyDidChange(this._content, '@each'); + }, this); + }, + + // .......................................................... + // LISTEN FOR NEW OBSERVERS AND OTHER EVENT LISTENERS + // Start monitoring keys based on who is listening... + + didAddListener: function(eventName) { + if (IS_OBSERVER.test(eventName)) { + this.beginObservingContentKey(eventName.slice(0, -7)); + } + }, + + didRemoveListener: function(eventName) { + if (IS_OBSERVER.test(eventName)) { + this.stopObservingContentKey(eventName.slice(0, -7)); + } + }, + + // .......................................................... + // CONTENT KEY OBSERVING + // Actual watch keys on the source content. + + beginObservingContentKey: function(keyName) { + var keys = this._keys; + if (!keys) keys = this._keys = {}; + if (!keys[keyName]) { + keys[keyName] = 1; + var content = this._content, + len = get(content, 'length'); + addObserverForContentKey(content, keyName, this, 0, len); + } else { + keys[keyName]++; + } + }, + + stopObservingContentKey: function(keyName) { + var keys = this._keys; + if (keys && (keys[keyName]>0) && (--keys[keyName]<=0)) { + var content = this._content, + len = get(content, 'length'); + removeObserverForContentKey(content, keyName, this, 0, len); + } + }, + + contentKeyWillChange: function(obj, keyName) { + Ember.propertyWillChange(this, keyName); + }, + + contentKeyDidChange: function(obj, keyName) { + Ember.propertyDidChange(this, keyName); + } + +}); + + + +})(); + + + +(function() { +/** +@module ember +@submodule ember-runtime +*/ + + +var get = Ember.get, set = Ember.set, replace = Ember.EnumerableUtils._replace; + +// Add Ember.Array to Array.prototype. Remove methods with native +// implementations and supply some more optimized versions of generic methods +// because they are so common. +var NativeArray = Ember.Mixin.create(Ember.MutableArray, Ember.Observable, Ember.Copyable, { + + // because length is a built-in property we need to know to just get the + // original property. + get: function(key) { + if (key==='length') return this.length; + else if ('number' === typeof key) return this[key]; + else return this._super(key); + }, + + objectAt: function(idx) { + return this[idx]; + }, + + // primitive for array support. + replace: function(idx, amt, objects) { + + if (this.isFrozen) throw Ember.FROZEN_ERROR; + + // if we replaced exactly the same number of items, then pass only the + // replaced range. Otherwise, pass the full remaining array length + // since everything has shifted + var len = objects ? get(objects, 'length') : 0; + this.arrayContentWillChange(idx, amt, len); + + if (len === 0) { + this.splice(idx, amt); + } else { + replace(this, idx, amt, objects); + } + + this.arrayContentDidChange(idx, amt, len); + return this; + }, + + // If you ask for an unknown property, then try to collect the value + // from member items. + unknownProperty: function(key, value) { + var ret;// = this.reducedProperty(key, value) ; + if ((value !== undefined) && ret === undefined) { + ret = this[key] = value; + } + return ret ; + }, + + // If browser did not implement indexOf natively, then override with + // specialized version + indexOf: function(object, startAt) { + var idx, len = this.length; + + if (startAt === undefined) startAt = 0; + else startAt = (startAt < 0) ? Math.ceil(startAt) : Math.floor(startAt); + if (startAt < 0) startAt += len; + + for(idx=startAt;idx=0;idx--) { + if (this[idx] === object) return idx ; + } + return -1; + }, + + copy: function(deep) { + if (deep) { + return this.map(function(item) { return Ember.copy(item, true); }); + } + + return this.slice(); + } +}); + +// Remove any methods implemented natively so we don't override them +var ignore = ['length']; +Ember.EnumerableUtils.forEach(NativeArray.keys(), function(methodName) { + if (Array.prototype[methodName]) ignore.push(methodName); +}); + +if (ignore.length>0) { + NativeArray = NativeArray.without.apply(NativeArray, ignore); +} + +/** + The NativeArray mixin contains the properties needed to to make the native + Array support Ember.MutableArray and all of its dependent APIs. Unless you + have `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Array` set to + false, this will be applied automatically. Otherwise you can apply the mixin + at anytime by calling `Ember.NativeArray.activate`. + + @class NativeArray + @namespace Ember + @uses Ember.MutableArray + @uses Ember.Observable + @uses Ember.Copyable +*/ +Ember.NativeArray = NativeArray; + +/** + Creates an `Ember.NativeArray` from an Array like object. + Does not modify the original object. Ember.A is not needed if + `Ember.EXTEND_PROTOTYPES` is `true` (the default value). However, + it is recommended that you use Ember.A when creating addons for + ember or when you can not guarantee that `Ember.EXTEND_PROTOTYPES` + will be `true`. + + Example + + ```js + var Pagination = Ember.CollectionView.extend({ + tagName: 'ul', + classNames: ['pagination'], + init: function() { + this._super(); + if (!this.get('content')) { + this.set('content', Ember.A([])); + } + } + }); + ``` + + @method A + @for Ember + @return {Ember.NativeArray} +*/ +Ember.A = function(arr) { + if (arr === undefined) { arr = []; } + return Ember.Array.detect(arr) ? arr : Ember.NativeArray.apply(arr); +}; + +/** + Activates the mixin on the Array.prototype if not already applied. Calling + this method more than once is safe. This will be called when ember is loaded + unless you have `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Array` + set to `false`. + + Example + + ```js + if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Array) { + Ember.NativeArray.activate(); + } + ``` + + @method activate + @for Ember.NativeArray + @static + @return {void} +*/ +Ember.NativeArray.activate = function() { + NativeArray.apply(Array.prototype); + + Ember.A = function(arr) { return arr || []; }; +}; + +if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Array) { + Ember.NativeArray.activate(); +} + + +})(); + + + +(function() { +/** +@module ember +@submodule ember-runtime +*/ + +var get = Ember.get, set = Ember.set, guidFor = Ember.guidFor, isNone = Ember.isNone, fmt = Ember.String.fmt; + +/** + An unordered collection of objects. + + A Set works a bit like an array except that its items are not ordered. You + can create a set to efficiently test for membership for an object. You can + also iterate through a set just like an array, even accessing objects by + index, however there is no guarantee as to their order. + + All Sets are observable via the Enumerable Observer API - which works + on any enumerable object including both Sets and Arrays. + + ## Creating a Set + + You can create a set like you would most objects using + `new Ember.Set()`. Most new sets you create will be empty, but you can + also initialize the set with some content by passing an array or other + enumerable of objects to the constructor. + + Finally, you can pass in an existing set and the set will be copied. You + can also create a copy of a set by calling `Ember.Set#copy()`. + + ```javascript + // creates a new empty set + var foundNames = new Ember.Set(); + + // creates a set with four names in it. + var names = new Ember.Set(["Charles", "Tom", "Juan", "Alex"]); // :P + + // creates a copy of the names set. + var namesCopy = new Ember.Set(names); + + // same as above. + var anotherNamesCopy = names.copy(); + ``` + + ## Adding/Removing Objects + + You generally add or remove objects from a set using `add()` or + `remove()`. You can add any type of object including primitives such as + numbers, strings, and booleans. + + Unlike arrays, objects can only exist one time in a set. If you call `add()` + on a set with the same object multiple times, the object will only be added + once. Likewise, calling `remove()` with the same object multiple times will + remove the object the first time and have no effect on future calls until + you add the object to the set again. + + NOTE: You cannot add/remove `null` or `undefined` to a set. Any attempt to do + so will be ignored. + + In addition to add/remove you can also call `push()`/`pop()`. Push behaves + just like `add()` but `pop()`, unlike `remove()` will pick an arbitrary + object, remove it and return it. This is a good way to use a set as a job + queue when you don't care which order the jobs are executed in. + + ## Testing for an Object + + To test for an object's presence in a set you simply call + `Ember.Set#contains()`. + + ## Observing changes + + When using `Ember.Set`, you can observe the `"[]"` property to be + alerted whenever the content changes. You can also add an enumerable + observer to the set to be notified of specific objects that are added and + removed from the set. See [Ember.Enumerable](/api/classes/Ember.Enumerable.html) + for more information on enumerables. + + This is often unhelpful. If you are filtering sets of objects, for instance, + it is very inefficient to re-filter all of the items each time the set + changes. It would be better if you could just adjust the filtered set based + on what was changed on the original set. The same issue applies to merging + sets, as well. + + ## Other Methods + + `Ember.Set` primary implements other mixin APIs. For a complete reference + on the methods you will use with `Ember.Set`, please consult these mixins. + The most useful ones will be `Ember.Enumerable` and + `Ember.MutableEnumerable` which implement most of the common iterator + methods you are used to on Array. + + Note that you can also use the `Ember.Copyable` and `Ember.Freezable` + APIs on `Ember.Set` as well. Once a set is frozen it can no longer be + modified. The benefit of this is that when you call `frozenCopy()` on it, + Ember will avoid making copies of the set. This allows you to write + code that can know with certainty when the underlying set data will or + will not be modified. + + @class Set + @namespace Ember + @extends Ember.CoreObject + @uses Ember.MutableEnumerable + @uses Ember.Copyable + @uses Ember.Freezable + @since Ember 0.9 +*/ +Ember.Set = Ember.CoreObject.extend(Ember.MutableEnumerable, Ember.Copyable, Ember.Freezable, + /** @scope Ember.Set.prototype */ { + + // .......................................................... + // IMPLEMENT ENUMERABLE APIS + // + + /** + This property will change as the number of objects in the set changes. + + @property length + @type number + @default 0 + */ + length: 0, + + /** + Clears the set. This is useful if you want to reuse an existing set + without having to recreate it. + + ```javascript + var colors = new Ember.Set(["red", "green", "blue"]); + colors.length; // 3 + colors.clear(); + colors.length; // 0 + ``` + + @method clear + @return {Ember.Set} An empty Set + */ + clear: function() { + if (this.isFrozen) { throw new Ember.Error(Ember.FROZEN_ERROR); } + + var len = get(this, 'length'); + if (len === 0) { return this; } + + var guid; + + this.enumerableContentWillChange(len, 0); + Ember.propertyWillChange(this, 'firstObject'); + Ember.propertyWillChange(this, 'lastObject'); + + for (var i=0; i < len; i++) { + guid = guidFor(this[i]); + delete this[guid]; + delete this[i]; + } + + set(this, 'length', 0); + + Ember.propertyDidChange(this, 'firstObject'); + Ember.propertyDidChange(this, 'lastObject'); + this.enumerableContentDidChange(len, 0); + + return this; + }, + + /** + Returns true if the passed object is also an enumerable that contains the + same objects as the receiver. + + ```javascript + var colors = ["red", "green", "blue"], + same_colors = new Ember.Set(colors); + + same_colors.isEqual(colors); // true + same_colors.isEqual(["purple", "brown"]); // false + ``` + + @method isEqual + @param {Ember.Set} obj the other object. + @return {Boolean} + */ + isEqual: function(obj) { + // fail fast + if (!Ember.Enumerable.detect(obj)) return false; + + var loc = get(this, 'length'); + if (get(obj, 'length') !== loc) return false; + + while(--loc >= 0) { + if (!obj.contains(this[loc])) return false; + } + + return true; + }, + + /** + Adds an object to the set. Only non-`null` objects can be added to a set + and those can only be added once. If the object is already in the set or + the passed value is null this method will have no effect. + + This is an alias for `Ember.MutableEnumerable.addObject()`. + + ```javascript + var colors = new Ember.Set(); + colors.add("blue"); // ["blue"] + colors.add("blue"); // ["blue"] + colors.add("red"); // ["blue", "red"] + colors.add(null); // ["blue", "red"] + colors.add(undefined); // ["blue", "red"] + ``` + + @method add + @param {Object} obj The object to add. + @return {Ember.Set} The set itself. + */ + add: Ember.aliasMethod('addObject'), + + /** + Removes the object from the set if it is found. If you pass a `null` value + or an object that is already not in the set, this method will have no + effect. This is an alias for `Ember.MutableEnumerable.removeObject()`. + + ```javascript + var colors = new Ember.Set(["red", "green", "blue"]); + colors.remove("red"); // ["blue", "green"] + colors.remove("purple"); // ["blue", "green"] + colors.remove(null); // ["blue", "green"] + ``` + + @method remove + @param {Object} obj The object to remove + @return {Ember.Set} The set itself. + */ + remove: Ember.aliasMethod('removeObject'), + + /** + Removes the last element from the set and returns it, or `null` if it's empty. + + ```javascript + var colors = new Ember.Set(["green", "blue"]); + colors.pop(); // "blue" + colors.pop(); // "green" + colors.pop(); // null + ``` + + @method pop + @return {Object} The removed object from the set or null. + */ + pop: function() { + if (get(this, 'isFrozen')) throw new Ember.Error(Ember.FROZEN_ERROR); + var obj = this.length > 0 ? this[this.length-1] : null; + this.remove(obj); + return obj; + }, + + /** + Inserts the given object on to the end of the set. It returns + the set itself. + + This is an alias for `Ember.MutableEnumerable.addObject()`. + + ```javascript + var colors = new Ember.Set(); + colors.push("red"); // ["red"] + colors.push("green"); // ["red", "green"] + colors.push("blue"); // ["red", "green", "blue"] + ``` + + @method push + @return {Ember.Set} The set itself. + */ + push: Ember.aliasMethod('addObject'), + + /** + Removes the last element from the set and returns it, or `null` if it's empty. + + This is an alias for `Ember.Set.pop()`. + + ```javascript + var colors = new Ember.Set(["green", "blue"]); + colors.shift(); // "blue" + colors.shift(); // "green" + colors.shift(); // null + ``` + + @method shift + @return {Object} The removed object from the set or null. + */ + shift: Ember.aliasMethod('pop'), + + /** + Inserts the given object on to the end of the set. It returns + the set itself. + + This is an alias of `Ember.Set.push()` + + ```javascript + var colors = new Ember.Set(); + colors.unshift("red"); // ["red"] + colors.unshift("green"); // ["red", "green"] + colors.unshift("blue"); // ["red", "green", "blue"] + ``` + + @method unshift + @return {Ember.Set} The set itself. + */ + unshift: Ember.aliasMethod('push'), + + /** + Adds each object in the passed enumerable to the set. + + This is an alias of `Ember.MutableEnumerable.addObjects()` + + ```javascript + var colors = new Ember.Set(); + colors.addEach(["red", "green", "blue"]); // ["red", "green", "blue"] + ``` + + @method addEach + @param {Ember.Enumerable} objects the objects to add. + @return {Ember.Set} The set itself. + */ + addEach: Ember.aliasMethod('addObjects'), + + /** + Removes each object in the passed enumerable to the set. + + This is an alias of `Ember.MutableEnumerable.removeObjects()` + + ```javascript + var colors = new Ember.Set(["red", "green", "blue"]); + colors.removeEach(["red", "blue"]); // ["green"] + ``` + + @method removeEach + @param {Ember.Enumerable} objects the objects to remove. + @return {Ember.Set} The set itself. + */ + removeEach: Ember.aliasMethod('removeObjects'), + + // .......................................................... + // PRIVATE ENUMERABLE SUPPORT + // + + init: function(items) { + this._super(); + if (items) this.addObjects(items); + }, + + // implement Ember.Enumerable + nextObject: function(idx) { + return this[idx]; + }, + + // more optimized version + firstObject: Ember.computed(function() { + return this.length > 0 ? this[0] : undefined; + }), + + // more optimized version + lastObject: Ember.computed(function() { + return this.length > 0 ? this[this.length-1] : undefined; + }), + + // implements Ember.MutableEnumerable + addObject: function(obj) { + if (get(this, 'isFrozen')) throw new Ember.Error(Ember.FROZEN_ERROR); + if (isNone(obj)) return this; // nothing to do + + var guid = guidFor(obj), + idx = this[guid], + len = get(this, 'length'), + added ; + + if (idx>=0 && idx=0 && idx=0; + }, + + copy: function() { + var C = this.constructor, ret = new C(), loc = get(this, 'length'); + set(ret, 'length', loc); + while(--loc>=0) { + ret[loc] = this[loc]; + ret[guidFor(this[loc])] = loc; + } + return ret; + }, + + toString: function() { + var len = this.length, idx, array = []; + for(idx = 0; idx < len; idx++) { + array[idx] = this[idx]; + } + return fmt("Ember.Set<%@>", [array.join(',')]); + } + +}); + +})(); + + + +(function() { +var DeferredMixin = Ember.DeferredMixin, // mixins/deferred + get = Ember.get; + +var Deferred = Ember.Object.extend(DeferredMixin); + +Deferred.reopenClass({ + promise: function(callback, binding) { + var deferred = Deferred.create(); + callback.call(binding, deferred); + return deferred; + } +}); + +Ember.Deferred = Deferred; + +})(); + + + +(function() { +var forEach = Ember.ArrayPolyfills.forEach; + +/** +@module ember +@submodule ember-runtime +*/ + +var loadHooks = Ember.ENV.EMBER_LOAD_HOOKS || {}; +var loaded = {}; + +/** + +Detects when a specific package of Ember (e.g. 'Ember.Handlebars') +has fully loaded and is available for extension. + +The provided `callback` will be called with the `name` passed +resolved from a string into the object: + +```javascript +Ember.onLoad('Ember.Handlebars' function(hbars){ + hbars.registerHelper(...); +}); +``` + + +@method onLoad +@for Ember +@param name {String} name of hook +@param callback {Function} callback to be called +*/ +Ember.onLoad = function(name, callback) { + var object; + + loadHooks[name] = loadHooks[name] || Ember.A(); + loadHooks[name].pushObject(callback); + + if (object = loaded[name]) { + callback(object); + } +}; + +/** + +Called when an Ember.js package (e.g Ember.Handlebars) has finished +loading. Triggers any callbacks registered for this event. + +@method runLoadHooks +@for Ember +@param name {String} name of hook +@param object {Object} object to pass to callbacks +*/ +Ember.runLoadHooks = function(name, object) { + loaded[name] = object; + + if (loadHooks[name]) { + forEach.call(loadHooks[name], function(callback) { + callback(object); + }); + } +}; + +})(); + + + +(function() { + +})(); + + + +(function() { +var get = Ember.get; + +/** +@module ember +@submodule ember-runtime +*/ + +/** + `Ember.ControllerMixin` provides a standard interface for all classes that + compose Ember's controller layer: `Ember.Controller`, + `Ember.ArrayController`, and `Ember.ObjectController`. + + @class ControllerMixin + @namespace Ember +*/ +Ember.ControllerMixin = Ember.Mixin.create(Ember.ActionHandler, { + /* ducktype as a controller */ + isController: true, + + /** + The object to which actions from the view should be sent. + + For example, when a Handlebars template uses the `{{action}}` helper, + it will attempt to send the action to the view's controller's `target`. + + By default, a controller's `target` is set to the router after it is + instantiated by `Ember.Application#initialize`. + + @property target + @default null + */ + target: null, + + container: null, + + parentController: null, + + store: null, + + model: Ember.computed.alias('content'), + + deprecatedSendHandles: function(actionName) { + return !!this[actionName]; + }, + + deprecatedSend: function(actionName) { + var args = [].slice.call(arguments, 1); + Ember.assert('' + this + " has the action " + actionName + " but it is not a function", typeof this[actionName] === 'function'); + Ember.deprecate('Action handlers implemented directly on controllers are deprecated in favor of action handlers on an `actions` object (' + actionName + ' on ' + this + ')', false); + this[actionName].apply(this, args); + return; + } +}); + +/** + @class Controller + @namespace Ember + @extends Ember.Object + @uses Ember.ControllerMixin +*/ +Ember.Controller = Ember.Object.extend(Ember.ControllerMixin); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-runtime +*/ + +var get = Ember.get, set = Ember.set, forEach = Ember.EnumerableUtils.forEach; + +/** + `Ember.SortableMixin` provides a standard interface for array proxies + to specify a sort order and maintain this sorting when objects are added, + removed, or updated without changing the implicit order of their underlying + content array: + + ```javascript + songs = [ + {trackNumber: 4, title: 'Ob-La-Di, Ob-La-Da'}, + {trackNumber: 2, title: 'Back in the U.S.S.R.'}, + {trackNumber: 3, title: 'Glass Onion'}, + ]; + + songsController = Ember.ArrayController.create({ + content: songs, + sortProperties: ['trackNumber'], + sortAscending: true + }); + + songsController.get('firstObject'); // {trackNumber: 2, title: 'Back in the U.S.S.R.'} + + songsController.addObject({trackNumber: 1, title: 'Dear Prudence'}); + songsController.get('firstObject'); // {trackNumber: 1, title: 'Dear Prudence'} + ``` + + If you add or remove the properties to sort by or change the sort direction the content + sort order will be automatically updated. + + ```javascript + songsController.set('sortProperties', ['title']); + songsController.get('firstObject'); // {trackNumber: 2, title: 'Back in the U.S.S.R.'} + + songsController.toggleProperty('sortAscending'); + songsController.get('firstObject'); // {trackNumber: 4, title: 'Ob-La-Di, Ob-La-Da'} + ``` + + SortableMixin works by sorting the arrangedContent array, which is the array that + arrayProxy displays. Due to the fact that the underlying 'content' array is not changed, that + array will not display the sorted list: + + ```javascript + songsController.get('content').get('firstObject'); // Returns the unsorted original content + songsController.get('firstObject'); // Returns the sorted content. + ``` + + Although the sorted content can also be accessed through the arrangedContent property, + it is preferable to use the proxied class and not the arrangedContent array directly. + + @class SortableMixin + @namespace Ember + @uses Ember.MutableEnumerable +*/ +Ember.SortableMixin = Ember.Mixin.create(Ember.MutableEnumerable, { + + /** + Specifies which properties dictate the arrangedContent's sort order. + + When specifying multiple properties the sorting will use properties + from the `sortProperties` array prioritized from first to last. + + @property {Array} sortProperties + */ + sortProperties: null, + + /** + Specifies the arrangedContent's sort direction + + @property {Boolean} sortAscending + */ + sortAscending: true, + + /** + The function used to compare two values. You can override this if you + want to do custom comparisons. Functions must be of the type expected by + Array#sort, i.e. + return 0 if the two parameters are equal, + return a negative value if the first parameter is smaller than the second or + return a positive value otherwise: + + ```javascript + function(x,y) { // These are assumed to be integers + if (x === y) + return 0; + return x < y ? -1 : 1; + } + ``` + + @property sortFunction + @type {Function} + @default Ember.compare + */ + sortFunction: Ember.compare, + + orderBy: function(item1, item2) { + var result = 0, + sortProperties = get(this, 'sortProperties'), + sortAscending = get(this, 'sortAscending'), + sortFunction = get(this, 'sortFunction'); + + Ember.assert("you need to define `sortProperties`", !!sortProperties); + + forEach(sortProperties, function(propertyName) { + if (result === 0) { + result = sortFunction(get(item1, propertyName), get(item2, propertyName)); + if ((result !== 0) && !sortAscending) { + result = (-1) * result; + } + } + }); + + return result; + }, + + destroy: function() { + var content = get(this, 'content'), + sortProperties = get(this, 'sortProperties'); + + if (content && sortProperties) { + forEach(content, function(item) { + forEach(sortProperties, function(sortProperty) { + Ember.removeObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + } + + return this._super(); + }, + + isSorted: Ember.computed.bool('sortProperties'), + + /** + Overrides the default arrangedContent from arrayProxy in order to sort by sortFunction. + Also sets up observers for each sortProperty on each item in the content Array. + + @property arrangedContent + */ + + arrangedContent: Ember.computed('content', 'sortProperties.@each', function(key, value) { + var content = get(this, 'content'), + isSorted = get(this, 'isSorted'), + sortProperties = get(this, 'sortProperties'), + self = this; + + if (content && isSorted) { + content = content.slice(); + content.sort(function(item1, item2) { + return self.orderBy(item1, item2); + }); + forEach(content, function(item) { + forEach(sortProperties, function(sortProperty) { + Ember.addObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + return Ember.A(content); + } + + return content; + }), + + _contentWillChange: Ember.beforeObserver('content', function() { + var content = get(this, 'content'), + sortProperties = get(this, 'sortProperties'); + + if (content && sortProperties) { + forEach(content, function(item) { + forEach(sortProperties, function(sortProperty) { + Ember.removeObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + } + + this._super(); + }), + + sortAscendingWillChange: Ember.beforeObserver('sortAscending', function() { + this._lastSortAscending = get(this, 'sortAscending'); + }), + + sortAscendingDidChange: Ember.observer('sortAscending', function() { + if (get(this, 'sortAscending') !== this._lastSortAscending) { + var arrangedContent = get(this, 'arrangedContent'); + arrangedContent.reverseObjects(); + } + }), + + contentArrayWillChange: function(array, idx, removedCount, addedCount) { + var isSorted = get(this, 'isSorted'); + + if (isSorted) { + var arrangedContent = get(this, 'arrangedContent'); + var removedObjects = array.slice(idx, idx+removedCount); + var sortProperties = get(this, 'sortProperties'); + + forEach(removedObjects, function(item) { + arrangedContent.removeObject(item); + + forEach(sortProperties, function(sortProperty) { + Ember.removeObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + } + + return this._super(array, idx, removedCount, addedCount); + }, + + contentArrayDidChange: function(array, idx, removedCount, addedCount) { + var isSorted = get(this, 'isSorted'), + sortProperties = get(this, 'sortProperties'); + + if (isSorted) { + var addedObjects = array.slice(idx, idx+addedCount); + + forEach(addedObjects, function(item) { + this.insertItemSorted(item); + + forEach(sortProperties, function(sortProperty) { + Ember.addObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + } + + return this._super(array, idx, removedCount, addedCount); + }, + + insertItemSorted: function(item) { + var arrangedContent = get(this, 'arrangedContent'); + var length = get(arrangedContent, 'length'); + + var idx = this._binarySearch(item, 0, length); + arrangedContent.insertAt(idx, item); + }, + + contentItemSortPropertyDidChange: function(item) { + var arrangedContent = get(this, 'arrangedContent'), + oldIndex = arrangedContent.indexOf(item), + leftItem = arrangedContent.objectAt(oldIndex - 1), + rightItem = arrangedContent.objectAt(oldIndex + 1), + leftResult = leftItem && this.orderBy(item, leftItem), + rightResult = rightItem && this.orderBy(item, rightItem); + + if (leftResult < 0 || rightResult > 0) { + arrangedContent.removeObject(item); + this.insertItemSorted(item); + } + }, + + _binarySearch: function(item, low, high) { + var mid, midItem, res, arrangedContent; + + if (low === high) { + return low; + } + + arrangedContent = get(this, 'arrangedContent'); + + mid = low + Math.floor((high - low) / 2); + midItem = arrangedContent.objectAt(mid); + + res = this.orderBy(midItem, item); + + if (res < 0) { + return this._binarySearch(item, mid+1, high); + } else if (res > 0) { + return this._binarySearch(item, low, mid); + } + + return mid; + } +}); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-runtime +*/ + +var get = Ember.get, set = Ember.set, forEach = Ember.EnumerableUtils.forEach, + replace = Ember.EnumerableUtils.replace; + +/** + `Ember.ArrayController` provides a way for you to publish a collection of + objects so that you can easily bind to the collection from a Handlebars + `#each` helper, an `Ember.CollectionView`, or other controllers. + + The advantage of using an `ArrayController` is that you only have to set up + your view bindings once; to change what's displayed, simply swap out the + `content` property on the controller. + + For example, imagine you wanted to display a list of items fetched via an XHR + request. Create an `Ember.ArrayController` and set its `content` property: + + ```javascript + MyApp.listController = Ember.ArrayController.create(); + + $.get('people.json', function(data) { + MyApp.listController.set('content', data); + }); + ``` + + Then, create a view that binds to your new controller: + + ```handlebars + {{#each MyApp.listController}} + {{firstName}} {{lastName}} + {{/each}} + ``` + + Although you are binding to the controller, the behavior of this controller + is to pass through any methods or properties to the underlying array. This + capability comes from `Ember.ArrayProxy`, which this class inherits from. + + Sometimes you want to display computed properties within the body of an + `#each` helper that depend on the underlying items in `content`, but are not + present on those items. To do this, set `itemController` to the name of a + controller (probably an `ObjectController`) that will wrap each individual item. + + For example: + + ```handlebars + {{#each post in controller}} +
          • {{title}} ({{titleLength}} characters)
          • + {{/each}} + ``` + + ```javascript + App.PostsController = Ember.ArrayController.extend({ + itemController: 'post' + }); + + App.PostController = Ember.ObjectController.extend({ + // the `title` property will be proxied to the underlying post. + + titleLength: function() { + return this.get('title').length; + }.property('title') + }); + ``` + + In some cases it is helpful to return a different `itemController` depending + on the particular item. Subclasses can do this by overriding + `lookupItemController`. + + For example: + + ```javascript + App.MyArrayController = Ember.ArrayController.extend({ + lookupItemController: function( object ) { + if (object.get('isSpecial')) { + return "special"; // use App.SpecialController + } else { + return "regular"; // use App.RegularController + } + } + }); + ``` + + The itemController instances will have a `parentController` property set to + either the the `parentController` property of the `ArrayController` + or to the `ArrayController` instance itself. + + @class ArrayController + @namespace Ember + @extends Ember.ArrayProxy + @uses Ember.SortableMixin + @uses Ember.ControllerMixin +*/ + +Ember.ArrayController = Ember.ArrayProxy.extend(Ember.ControllerMixin, + Ember.SortableMixin, { + + /** + The controller used to wrap items, if any. + + @property itemController + @type String + @default null + */ + itemController: null, + + /** + Return the name of the controller to wrap items, or `null` if items should + be returned directly. The default implementation simply returns the + `itemController` property, but subclasses can override this method to return + different controllers for different objects. + + For example: + + ```javascript + App.MyArrayController = Ember.ArrayController.extend({ + lookupItemController: function( object ) { + if (object.get('isSpecial')) { + return "special"; // use App.SpecialController + } else { + return "regular"; // use App.RegularController + } + } + }); + ``` + + @method lookupItemController + @param {Object} object + @return {String} + */ + lookupItemController: function(object) { + return get(this, 'itemController'); + }, + + objectAtContent: function(idx) { + var length = get(this, 'length'), + arrangedContent = get(this,'arrangedContent'), + object = arrangedContent && arrangedContent.objectAt(idx); + + if (idx >= 0 && idx < length) { + var controllerClass = this.lookupItemController(object); + if (controllerClass) { + return this.controllerAt(idx, object, controllerClass); + } + } + + // When `controllerClass` is falsy, we have not opted in to using item + // controllers, so return the object directly. + + // When the index is out of range, we want to return the "out of range" + // value, whatever that might be. Rather than make assumptions + // (e.g. guessing `null` or `undefined`) we defer this to `arrangedContent`. + return object; + }, + + arrangedContentDidChange: function() { + this._super(); + this._resetSubControllers(); + }, + + arrayContentDidChange: function(idx, removedCnt, addedCnt) { + var subControllers = get(this, '_subControllers'), + subControllersToRemove = subControllers.slice(idx, idx+removedCnt); + + forEach(subControllersToRemove, function(subController) { + if (subController) { subController.destroy(); } + }); + + replace(subControllers, idx, removedCnt, new Array(addedCnt)); + + // The shadow array of subcontrollers must be updated before we trigger + // observers, otherwise observers will get the wrong subcontainer when + // calling `objectAt` + this._super(idx, removedCnt, addedCnt); + }, + + init: function() { + this._super(); + + this.set('_subControllers', Ember.A()); + }, + + content: Ember.computed(function () { + return Ember.A(); + }), + + controllerAt: function(idx, object, controllerClass) { + var container = get(this, 'container'), + subControllers = get(this, '_subControllers'), + subController = subControllers[idx], + factory, fullName; + + if (subController) { return subController; } + + fullName = "controller:" + controllerClass; + + if (!container.has(fullName)) { + throw new Ember.Error('Could not resolve itemController: "' + controllerClass + '"'); + } + + subController = container.lookupFactory(fullName).create({ + target: this, + parentController: get(this, 'parentController') || this, + content: object + }); + + subControllers[idx] = subController; + + return subController; + }, + + _subControllers: null, + + _resetSubControllers: function() { + var subControllers = get(this, '_subControllers'); + if (subControllers) { + forEach(subControllers, function(subController) { + if (subController) { subController.destroy(); } + }); + } + + this.set('_subControllers', Ember.A()); + } +}); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-runtime +*/ + +/** + `Ember.ObjectController` is part of Ember's Controller layer. It is intended + to wrap a single object, proxying unhandled attempts to `get` and `set` to the underlying + content object, and to forward unhandled action attempts to its `target`. + + `Ember.ObjectController` derives this functionality from its superclass + `Ember.ObjectProxy` and the `Ember.ControllerMixin` mixin. + + @class ObjectController + @namespace Ember + @extends Ember.ObjectProxy + @uses Ember.ControllerMixin +**/ +Ember.ObjectController = Ember.ObjectProxy.extend(Ember.ControllerMixin); + +})(); + + + +(function() { + +})(); + + + +(function() { +/** +Ember Runtime + +@module ember +@submodule ember-runtime +@requires ember-metal +*/ + +})(); + +(function() { +/** +@module ember +@submodule ember-views +*/ + +var jQuery = this.jQuery || (Ember.imports && Ember.imports.jQuery); +if (!jQuery && typeof require === 'function') { + jQuery = require('jquery'); +} + +Ember.assert("Ember Views require jQuery 1.7, 1.8, 1.9, 1.10, or 2.0", jQuery && (jQuery().jquery.match(/^((1\.(7|8|9|10))|2.0)(\.\d+)?(pre|rc\d?)?/) || Ember.ENV.FORCE_JQUERY)); + +/** + Alias for jQuery + + @method $ + @for Ember +*/ +Ember.$ = jQuery; + +})(); + + + +(function() { +/** +@module ember +@submodule ember-views +*/ +if (Ember.$) { + // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#dndevents + var dragEvents = Ember.String.w('dragstart drag dragenter dragleave dragover drop dragend'); + + // Copies the `dataTransfer` property from a browser event object onto the + // jQuery event object for the specified events + Ember.EnumerableUtils.forEach(dragEvents, function(eventName) { + Ember.$.event.fixHooks[eventName] = { props: ['dataTransfer'] }; + }); +} + +})(); + + + +(function() { +/** +@module ember +@submodule ember-views +*/ + +/* BEGIN METAMORPH HELPERS */ + +// Internet Explorer prior to 9 does not allow setting innerHTML if the first element +// is a "zero-scope" element. This problem can be worked around by making +// the first node an invisible text node. We, like Modernizr, use ­ + +var needsShy = this.document && (function() { + var testEl = document.createElement('div'); + testEl.innerHTML = "
            "; + testEl.firstChild.innerHTML = ""; + return testEl.firstChild.innerHTML === ''; +})(); + +// IE 8 (and likely earlier) likes to move whitespace preceeding +// a script tag to appear after it. This means that we can +// accidentally remove whitespace when updating a morph. +var movesWhitespace = this.document && (function() { + var testEl = document.createElement('div'); + testEl.innerHTML = "Test: Value"; + return testEl.childNodes[0].nodeValue === 'Test:' && + testEl.childNodes[2].nodeValue === ' Value'; +})(); + +// Use this to find children by ID instead of using jQuery +var findChildById = function(element, id) { + if (element.getAttribute('id') === id) { return element; } + + var len = element.childNodes.length, idx, node, found; + for (idx=0; idx 0) { + var len = matches.length, idx; + for (idx=0; idxTest'); + canSet = el.options.length === 1; + } + + innerHTMLTags[tagName] = canSet; + + return canSet; +}; + +var setInnerHTML = function(element, html) { + var tagName = element.tagName; + + if (canSetInnerHTML(tagName)) { + setInnerHTMLWithoutFix(element, html); + } else { + // Firefox versions < 11 do not have support for element.outerHTML. + var outerHTML = element.outerHTML || new XMLSerializer().serializeToString(element); + Ember.assert("Can't set innerHTML on "+element.tagName+" in this browser", outerHTML); + + var startTag = outerHTML.match(new RegExp("<"+tagName+"([^>]*)>", 'i'))[0], + endTag = ''; + + var wrapper = document.createElement('div'); + setInnerHTMLWithoutFix(wrapper, startTag + html + endTag); + element = wrapper.firstChild; + while (element.tagName !== tagName) { + element = element.nextSibling; + } + } + + return element; +}; + +function isSimpleClick(event) { + var modifier = event.shiftKey || event.metaKey || event.altKey || event.ctrlKey, + secondaryClick = event.which > 1; // IE9 may return undefined + + return !modifier && !secondaryClick; +} + +Ember.ViewUtils = { + setInnerHTML: setInnerHTML, + isSimpleClick: isSimpleClick +}; + +})(); + + + +(function() { +/** +@module ember +@submodule ember-views +*/ + +var get = Ember.get, set = Ember.set; + +var ClassSet = function() { + this.seen = {}; + this.list = []; +}; + +ClassSet.prototype = { + add: function(string) { + if (string in this.seen) { return; } + this.seen[string] = true; + + this.list.push(string); + }, + + toDOM: function() { + return this.list.join(" "); + } +}; + +var BAD_TAG_NAME_TEST_REGEXP = /[^a-zA-Z0-9\-]/; +var BAD_TAG_NAME_REPLACE_REGEXP = /[^a-zA-Z0-9\-]/g; + +function stripTagName(tagName) { + if (!tagName) { + return tagName; + } + + if (!BAD_TAG_NAME_TEST_REGEXP.test(tagName)) { + return tagName; + } + + return tagName.replace(BAD_TAG_NAME_REPLACE_REGEXP, ''); +} + +var BAD_CHARS_REGEXP = /&(?!\w+;)|[<>"'`]/g; +var POSSIBLE_CHARS_REGEXP = /[&<>"'`]/; + +function escapeAttribute(value) { + // Stolen shamelessly from Handlebars + + var escape = { + "<": "<", + ">": ">", + '"': """, + "'": "'", + "`": "`" + }; + + var escapeChar = function(chr) { + return escape[chr] || "&"; + }; + + var string = value.toString(); + + if(!POSSIBLE_CHARS_REGEXP.test(string)) { return string; } + return string.replace(BAD_CHARS_REGEXP, escapeChar); +} + +// IE 6/7 have bugs arond setting names on inputs during creation. +// From http://msdn.microsoft.com/en-us/library/ie/ms536389(v=vs.85).aspx: +// "To include the NAME attribute at run time on objects created with the createElement method, use the eTag." +var canSetNameOnInputs = (function() { + var div = document.createElement('div'), + el = document.createElement('input'); + + el.setAttribute('name', 'foo'); + div.appendChild(el); + + return !!div.innerHTML.match('foo'); +})(); + +/** + `Ember.RenderBuffer` gathers information regarding the a view and generates the + final representation. `Ember.RenderBuffer` will generate HTML which can be pushed + to the DOM. + + ```javascript + var buffer = Ember.RenderBuffer('div'); + ``` + + @class RenderBuffer + @namespace Ember + @constructor + @param {String} tagName tag name (such as 'div' or 'p') used for the buffer +*/ +Ember.RenderBuffer = function(tagName) { + return new Ember._RenderBuffer(tagName); +}; + +Ember._RenderBuffer = function(tagName) { + this.tagNames = [tagName || null]; + this.buffer = ""; +}; + +Ember._RenderBuffer.prototype = +/** @scope Ember.RenderBuffer.prototype */ { + + // The root view's element + _element: null, + + _hasElement: true, + + /** + @private + + An internal set used to de-dupe class names when `addClass()` is + used. After each call to `addClass()`, the `classes` property + will be updated. + + @property elementClasses + @type Array + @default [] + */ + elementClasses: null, + + /** + Array of class names which will be applied in the class attribute. + + You can use `setClasses()` to set this property directly. If you + use `addClass()`, it will be maintained for you. + + @property classes + @type Array + @default [] + */ + classes: null, + + /** + The id in of the element, to be applied in the id attribute. + + You should not set this property yourself, rather, you should use + the `id()` method of `Ember.RenderBuffer`. + + @property elementId + @type String + @default null + */ + elementId: null, + + /** + A hash keyed on the name of the attribute and whose value will be + applied to that attribute. For example, if you wanted to apply a + `data-view="Foo.bar"` property to an element, you would set the + elementAttributes hash to `{'data-view':'Foo.bar'}`. + + You should not maintain this hash yourself, rather, you should use + the `attr()` method of `Ember.RenderBuffer`. + + @property elementAttributes + @type Hash + @default {} + */ + elementAttributes: null, + + /** + A hash keyed on the name of the properties and whose value will be + applied to that property. For example, if you wanted to apply a + `checked=true` property to an element, you would set the + elementProperties hash to `{'checked':true}`. + + You should not maintain this hash yourself, rather, you should use + the `prop()` method of `Ember.RenderBuffer`. + + @property elementProperties + @type Hash + @default {} + */ + elementProperties: null, + + /** + The tagname of the element an instance of `Ember.RenderBuffer` represents. + + Usually, this gets set as the first parameter to `Ember.RenderBuffer`. For + example, if you wanted to create a `p` tag, then you would call + + ```javascript + Ember.RenderBuffer('p') + ``` + + @property elementTag + @type String + @default null + */ + elementTag: null, + + /** + A hash keyed on the name of the style attribute and whose value will + be applied to that attribute. For example, if you wanted to apply a + `background-color:black;` style to an element, you would set the + elementStyle hash to `{'background-color':'black'}`. + + You should not maintain this hash yourself, rather, you should use + the `style()` method of `Ember.RenderBuffer`. + + @property elementStyle + @type Hash + @default {} + */ + elementStyle: null, + + /** + Nested `RenderBuffers` will set this to their parent `RenderBuffer` + instance. + + @property parentBuffer + @type Ember._RenderBuffer + */ + parentBuffer: null, + + /** + Adds a string of HTML to the `RenderBuffer`. + + @method push + @param {String} string HTML to push into the buffer + @chainable + */ + push: function(string) { + this.buffer += string; + return this; + }, + + /** + Adds a class to the buffer, which will be rendered to the class attribute. + + @method addClass + @param {String} className Class name to add to the buffer + @chainable + */ + addClass: function(className) { + // lazily create elementClasses + this.elementClasses = (this.elementClasses || new ClassSet()); + this.elementClasses.add(className); + this.classes = this.elementClasses.list; + + return this; + }, + + setClasses: function(classNames) { + this.classes = classNames; + }, + + /** + Sets the elementID to be used for the element. + + @method id + @param {String} id + @chainable + */ + id: function(id) { + this.elementId = id; + return this; + }, + + // duck type attribute functionality like jQuery so a render buffer + // can be used like a jQuery object in attribute binding scenarios. + + /** + Adds an attribute which will be rendered to the element. + + @method attr + @param {String} name The name of the attribute + @param {String} value The value to add to the attribute + @chainable + @return {Ember.RenderBuffer|String} this or the current attribute value + */ + attr: function(name, value) { + var attributes = this.elementAttributes = (this.elementAttributes || {}); + + if (arguments.length === 1) { + return attributes[name]; + } else { + attributes[name] = value; + } + + return this; + }, + + /** + Remove an attribute from the list of attributes to render. + + @method removeAttr + @param {String} name The name of the attribute + @chainable + */ + removeAttr: function(name) { + var attributes = this.elementAttributes; + if (attributes) { delete attributes[name]; } + + return this; + }, + + /** + Adds an property which will be rendered to the element. + + @method prop + @param {String} name The name of the property + @param {String} value The value to add to the property + @chainable + @return {Ember.RenderBuffer|String} this or the current property value + */ + prop: function(name, value) { + var properties = this.elementProperties = (this.elementProperties || {}); + + if (arguments.length === 1) { + return properties[name]; + } else { + properties[name] = value; + } + + return this; + }, + + /** + Remove an property from the list of properties to render. + + @method removeProp + @param {String} name The name of the property + @chainable + */ + removeProp: function(name) { + var properties = this.elementProperties; + if (properties) { delete properties[name]; } + + return this; + }, + + /** + Adds a style to the style attribute which will be rendered to the element. + + @method style + @param {String} name Name of the style + @param {String} value + @chainable + */ + style: function(name, value) { + this.elementStyle = (this.elementStyle || {}); + + this.elementStyle[name] = value; + return this; + }, + + begin: function(tagName) { + this.tagNames.push(tagName || null); + return this; + }, + + pushOpeningTag: function() { + var tagName = this.currentTagName(); + if (!tagName) { return; } + + if (this._hasElement && !this._element && this.buffer.length === 0) { + this._element = this.generateElement(); + return; + } + + var buffer = this.buffer, + id = this.elementId, + classes = this.classes, + attrs = this.elementAttributes, + props = this.elementProperties, + style = this.elementStyle, + attr, prop; + + buffer += '<' + stripTagName(tagName); + + if (id) { + buffer += ' id="' + escapeAttribute(id) + '"'; + this.elementId = null; + } + if (classes) { + buffer += ' class="' + escapeAttribute(classes.join(' ')) + '"'; + this.classes = null; + } + + if (style) { + buffer += ' style="'; + + for (prop in style) { + if (style.hasOwnProperty(prop)) { + buffer += prop + ':' + escapeAttribute(style[prop]) + ';'; + } + } + + buffer += '"'; + + this.elementStyle = null; + } + + if (attrs) { + for (attr in attrs) { + if (attrs.hasOwnProperty(attr)) { + buffer += ' ' + attr + '="' + escapeAttribute(attrs[attr]) + '"'; + } + } + + this.elementAttributes = null; + } + + if (props) { + for (prop in props) { + if (props.hasOwnProperty(prop)) { + var value = props[prop]; + if (value || typeof(value) === 'number') { + if (value === true) { + buffer += ' ' + prop + '="' + prop + '"'; + } else { + buffer += ' ' + prop + '="' + escapeAttribute(props[prop]) + '"'; + } + } + } + } + + this.elementProperties = null; + } + + buffer += '>'; + this.buffer = buffer; + }, + + pushClosingTag: function() { + var tagName = this.tagNames.pop(); + if (tagName) { this.buffer += ''; } + }, + + currentTagName: function() { + return this.tagNames[this.tagNames.length-1]; + }, + + generateElement: function() { + var tagName = this.tagNames.pop(), // pop since we don't need to close + id = this.elementId, + classes = this.classes, + attrs = this.elementAttributes, + props = this.elementProperties, + style = this.elementStyle, + styleBuffer = '', attr, prop, tagString; + + if (attrs && attrs.name && !canSetNameOnInputs) { + // IE allows passing a tag to createElement. See note on `canSetNameOnInputs` above as well. + tagString = '<'+stripTagName(tagName)+' name="'+escapeAttribute(attrs.name)+'">'; + } else { + tagString = tagName; + } + + var element = document.createElement(tagString), + $element = Ember.$(element); + + if (id) { + $element.attr('id', id); + this.elementId = null; + } + if (classes) { + $element.attr('class', classes.join(' ')); + this.classes = null; + } + + if (style) { + for (prop in style) { + if (style.hasOwnProperty(prop)) { + styleBuffer += (prop + ':' + style[prop] + ';'); + } + } + + $element.attr('style', styleBuffer); + + this.elementStyle = null; + } + + if (attrs) { + for (attr in attrs) { + if (attrs.hasOwnProperty(attr)) { + $element.attr(attr, attrs[attr]); + } + } + + this.elementAttributes = null; + } + + if (props) { + for (prop in props) { + if (props.hasOwnProperty(prop)) { + $element.prop(prop, props[prop]); + } + } + + this.elementProperties = null; + } + + return element; + }, + + /** + @method element + @return {DOMElement} The element corresponding to the generated HTML + of this buffer + */ + element: function() { + var html = this.innerString(); + + if (html) { + this._element = Ember.ViewUtils.setInnerHTML(this._element, html); + } + + return this._element; + }, + + /** + Generates the HTML content for this buffer. + + @method string + @return {String} The generated HTML + */ + string: function() { + if (this._hasElement && this._element) { + // Firefox versions < 11 do not have support for element.outerHTML. + var thisElement = this.element(), outerHTML = thisElement.outerHTML; + if (typeof outerHTML === 'undefined') { + return Ember.$('
            ').append(thisElement).html(); + } + return outerHTML; + } else { + return this.innerString(); + } + }, + + innerString: function() { + return this.buffer; + } +}; + +})(); + + + +(function() { +/** +@module ember +@submodule ember-views +*/ + +var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt; + +/** + `Ember.EventDispatcher` handles delegating browser events to their + corresponding `Ember.Views.` For example, when you click on a view, + `Ember.EventDispatcher` ensures that that view's `mouseDown` method gets + called. + + @class EventDispatcher + @namespace Ember + @private + @extends Ember.Object +*/ +Ember.EventDispatcher = Ember.Object.extend(/** @scope Ember.EventDispatcher.prototype */{ + + /** + The set of events names (and associated handler function names) to be setup + and dispatched by the `EventDispatcher`. Custom events can added to this list at setup + time, generally via the `Ember.Application.customEvents` hash. Only override this + default set to prevent the EventDispatcher from listening on some events all together. + + This set will be modified by `setup` to also include any events added at that time. + + @property events + @type Object + */ + events: { + touchstart : 'touchStart', + touchmove : 'touchMove', + touchend : 'touchEnd', + touchcancel : 'touchCancel', + keydown : 'keyDown', + keyup : 'keyUp', + keypress : 'keyPress', + mousedown : 'mouseDown', + mouseup : 'mouseUp', + contextmenu : 'contextMenu', + click : 'click', + dblclick : 'doubleClick', + mousemove : 'mouseMove', + focusin : 'focusIn', + focusout : 'focusOut', + mouseenter : 'mouseEnter', + mouseleave : 'mouseLeave', + submit : 'submit', + input : 'input', + change : 'change', + dragstart : 'dragStart', + drag : 'drag', + dragenter : 'dragEnter', + dragleave : 'dragLeave', + dragover : 'dragOver', + drop : 'drop', + dragend : 'dragEnd' + }, + + /** + @private + + The root DOM element to which event listeners should be attached. Event + listeners will be attached to the document unless this is overridden. + + Can be specified as a DOMElement or a selector string. + + The default body is a string since this may be evaluated before document.body + exists in the DOM. + + @property rootElement + @type DOMElement + @default 'body' + */ + rootElement: 'body', + + /** + @private + + Sets up event listeners for standard browser events. + + This will be called after the browser sends a `DOMContentReady` event. By + default, it will set up all of the listeners on the document body. If you + would like to register the listeners on a different element, set the event + dispatcher's `root` property. + + @method setup + @param addedEvents {Hash} + */ + setup: function(addedEvents, rootElement) { + var event, events = get(this, 'events'); + + Ember.$.extend(events, addedEvents || {}); + + + if (!Ember.isNone(rootElement)) { + set(this, 'rootElement', rootElement); + } + + rootElement = Ember.$(get(this, 'rootElement')); + + Ember.assert(fmt('You cannot use the same root element (%@) multiple times in an Ember.Application', [rootElement.selector || rootElement[0].tagName]), !rootElement.is('.ember-application')); + Ember.assert('You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', !rootElement.closest('.ember-application').length); + Ember.assert('You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', !rootElement.find('.ember-application').length); + + rootElement.addClass('ember-application'); + + Ember.assert('Unable to add "ember-application" class to rootElement. Make sure you set rootElement to the body or an element in the body.', rootElement.is('.ember-application')); + + for (event in events) { + if (events.hasOwnProperty(event)) { + this.setupHandler(rootElement, event, events[event]); + } + } + }, + + /** + @private + + Registers an event listener on the document. If the given event is + triggered, the provided event handler will be triggered on the target view. + + If the target view does not implement the event handler, or if the handler + returns `false`, the parent view will be called. The event will continue to + bubble to each successive parent view until it reaches the top. + + For example, to have the `mouseDown` method called on the target view when + a `mousedown` event is received from the browser, do the following: + + ```javascript + setupHandler('mousedown', 'mouseDown'); + ``` + + @method setupHandler + @param {Element} rootElement + @param {String} event the browser-originated event to listen to + @param {String} eventName the name of the method to call on the view + */ + setupHandler: function(rootElement, event, eventName) { + var self = this; + + rootElement.on(event + '.ember', '.ember-view', function(evt, triggeringManager) { + return Ember.handleErrors(function() { + var view = Ember.View.views[this.id], + result = true, manager = null; + + manager = self._findNearestEventManager(view,eventName); + + if (manager && manager !== triggeringManager) { + result = self._dispatchEvent(manager, evt, eventName, view); + } else if (view) { + result = self._bubbleEvent(view,evt,eventName); + } else { + evt.stopPropagation(); + } + + return result; + }, this); + }); + + rootElement.on(event + '.ember', '[data-ember-action]', function(evt) { + return Ember.handleErrors(function() { + var actionId = Ember.$(evt.currentTarget).attr('data-ember-action'), + action = Ember.Handlebars.ActionHelper.registeredActions[actionId]; + + // We have to check for action here since in some cases, jQuery will trigger + // an event on `removeChild` (i.e. focusout) after we've already torn down the + // action handlers for the view. + if (action && action.eventName === eventName) { + return action.handler(evt); + } + }, this); + }); + }, + + _findNearestEventManager: function(view, eventName) { + var manager = null; + + while (view) { + manager = get(view, 'eventManager'); + if (manager && manager[eventName]) { break; } + + view = get(view, 'parentView'); + } + + return manager; + }, + + _dispatchEvent: function(object, evt, eventName, view) { + var result = true; + + var handler = object[eventName]; + if (Ember.typeOf(handler) === 'function') { + result = Ember.run(function() { + return handler.call(object, evt, view); + }); + // Do not preventDefault in eventManagers. + evt.stopPropagation(); + } + else { + result = this._bubbleEvent(view, evt, eventName); + } + + return result; + }, + + _bubbleEvent: function(view, evt, eventName) { + return Ember.run(function() { + return view.handleEvent(eventName, evt); + }); + }, + + destroy: function() { + var rootElement = get(this, 'rootElement'); + Ember.$(rootElement).off('.ember', '**').removeClass('ember-application'); + return this._super(); + } +}); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-views +*/ + +// Add a new named queue for rendering views that happens +// after bindings have synced, and a queue for scheduling actions +// that that should occur after view rendering. +var queues = Ember.run.queues, + indexOf = Ember.ArrayPolyfills.indexOf; +queues.splice(indexOf.call(queues, 'actions')+1, 0, 'render', 'afterRender'); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-views +*/ + +var get = Ember.get, set = Ember.set; + +// Original class declaration and documentation in runtime/lib/controllers/controller.js +// NOTE: It may be possible with YUIDoc to combine docs in two locations + +/** +Additional methods for the ControllerMixin + +@class ControllerMixin +@namespace Ember +*/ +Ember.ControllerMixin.reopen({ + target: null, + namespace: null, + view: null, + container: null, + _childContainers: null, + + init: function() { + this._super(); + set(this, '_childContainers', {}); + }, + + _modelDidChange: Ember.observer('model', function() { + var containers = get(this, '_childContainers'); + + for (var prop in containers) { + if (!containers.hasOwnProperty(prop)) { continue; } + containers[prop].destroy(); + } + + set(this, '_childContainers', {}); + }) +}); + +})(); + + + +(function() { + +})(); + + + +(function() { +var states = {}; + +/** +@module ember +@submodule ember-views +*/ + +var get = Ember.get, set = Ember.set; +var guidFor = Ember.guidFor; +var a_forEach = Ember.EnumerableUtils.forEach; +var a_addObject = Ember.EnumerableUtils.addObject; +var meta = Ember.meta; + +var childViewsProperty = Ember.computed(function() { + var childViews = this._childViews, ret = Ember.A(), view = this; + + a_forEach(childViews, function(view) { + var currentChildViews; + if (view.isVirtual) { + if (currentChildViews = get(view, 'childViews')) { + ret.pushObjects(currentChildViews); + } + } else { + ret.push(view); + } + }); + + ret.replace = function (idx, removedCount, addedViews) { + if (view instanceof Ember.ContainerView) { + Ember.deprecate("Manipulating an Ember.ContainerView through its childViews property is deprecated. Please use the ContainerView instance itself as an Ember.MutableArray."); + return view.replace(idx, removedCount, addedViews); + } + throw new Ember.Error("childViews is immutable"); + }; + + return ret; +}); + +Ember.warn("The VIEW_PRESERVES_CONTEXT flag has been removed and the functionality can no longer be disabled.", Ember.ENV.VIEW_PRESERVES_CONTEXT !== false); + +/** + Global hash of shared templates. This will automatically be populated + by the build tools so that you can store your Handlebars templates in + separate files that get loaded into JavaScript at buildtime. + + @property TEMPLATES + @for Ember + @type Hash +*/ +Ember.TEMPLATES = {}; + +/** + `Ember.CoreView` is an abstract class that exists to give view-like behavior + to both Ember's main view class `Ember.View` and other classes like + `Ember._SimpleMetamorphView` that don't need the fully functionaltiy of + `Ember.View`. + + Unless you have specific needs for `CoreView`, you will use `Ember.View` + in your applications. + + @class CoreView + @namespace Ember + @extends Ember.Object + @uses Ember.Evented +*/ + +Ember.CoreView = Ember.Object.extend(Ember.Evented, Ember.ActionHandler, { + isView: true, + + states: states, + + init: function() { + this._super(); + this.transitionTo('preRender'); + }, + + /** + If the view is currently inserted into the DOM of a parent view, this + property will point to the parent of the view. + + @property parentView + @type Ember.View + @default null + */ + parentView: Ember.computed(function() { + var parent = this._parentView; + + if (parent && parent.isVirtual) { + return get(parent, 'parentView'); + } else { + return parent; + } + }).property('_parentView'), + + state: null, + + _parentView: null, + + // return the current view, not including virtual views + concreteView: Ember.computed(function() { + if (!this.isVirtual) { return this; } + else { return get(this, 'parentView'); } + }).property('parentView'), + + instrumentName: 'core_view', + + instrumentDetails: function(hash) { + hash.object = this.toString(); + }, + + /** + @private + + Invoked by the view system when this view needs to produce an HTML + representation. This method will create a new render buffer, if needed, + then apply any default attributes, such as class names and visibility. + Finally, the `render()` method is invoked, which is responsible for + doing the bulk of the rendering. + + You should not need to override this method; instead, implement the + `template` property, or if you need more control, override the `render` + method. + + @method renderToBuffer + @param {Ember.RenderBuffer} buffer the render buffer. If no buffer is + passed, a default buffer, using the current view's `tagName`, will + be used. + */ + renderToBuffer: function(parentBuffer, bufferOperation) { + var name = 'render.' + this.instrumentName, + details = {}; + + this.instrumentDetails(details); + + return Ember.instrument(name, details, function() { + return this._renderToBuffer(parentBuffer, bufferOperation); + }, this); + }, + + _renderToBuffer: function(parentBuffer, bufferOperation) { + // If this is the top-most view, start a new buffer. Otherwise, + // create a new buffer relative to the original using the + // provided buffer operation (for example, `insertAfter` will + // insert a new buffer after the "parent buffer"). + var tagName = this.tagName; + + if (tagName === null || tagName === undefined) { + tagName = 'div'; + } + + var buffer = this.buffer = parentBuffer && parentBuffer.begin(tagName) || Ember.RenderBuffer(tagName); + this.transitionTo('inBuffer', false); + + this.beforeRender(buffer); + this.render(buffer); + this.afterRender(buffer); + + return buffer; + }, + + /** + @private + + Override the default event firing from `Ember.Evented` to + also call methods with the given name. + + @method trigger + @param name {String} + */ + trigger: function(name) { + this._super.apply(this, arguments); + var method = this[name]; + if (method) { + var args = [], i, l; + for (i = 1, l = arguments.length; i < l; i++) { + args.push(arguments[i]); + } + return method.apply(this, args); + } + }, + + deprecatedSendHandles: function(actionName) { + return !!this[actionName]; + }, + + deprecatedSend: function(actionName) { + var args = [].slice.call(arguments, 1); + Ember.assert('' + this + " has the action " + actionName + " but it is not a function", typeof this[actionName] === 'function'); + Ember.deprecate('Action handlers implemented directly on views are deprecated in favor of action handlers on an `actions` object (' + actionName + ' on ' + this + ')', false); + this[actionName].apply(this, args); + return; + }, + + has: function(name) { + return Ember.typeOf(this[name]) === 'function' || this._super(name); + }, + + destroy: function() { + var parent = this._parentView; + + if (!this._super()) { return; } + + // destroy the element -- this will avoid each child view destroying + // the element over and over again... + if (!this.removedFromDOM) { this.destroyElement(); } + + // remove from parent if found. Don't call removeFromParent, + // as removeFromParent will try to remove the element from + // the DOM again. + if (parent) { parent.removeChild(this); } + + this.transitionTo('destroying', false); + + return this; + }, + + clearRenderedChildren: Ember.K, + triggerRecursively: Ember.K, + invokeRecursively: Ember.K, + transitionTo: Ember.K, + destroyElement: Ember.K +}); + +var ViewCollection = Ember._ViewCollection = function(initialViews) { + var views = this.views = initialViews || []; + this.length = views.length; +}; + +ViewCollection.prototype = { + length: 0, + + trigger: function(eventName) { + var views = this.views, view; + for (var i = 0, l = views.length; i < l; i++) { + view = views[i]; + if (view.trigger) { view.trigger(eventName); } + } + }, + + triggerRecursively: function(eventName) { + var views = this.views; + for (var i = 0, l = views.length; i < l; i++) { + views[i].triggerRecursively(eventName); + } + }, + + invokeRecursively: function(fn) { + var views = this.views, view; + + for (var i = 0, l = views.length; i < l; i++) { + view = views[i]; + fn(view); + } + }, + + transitionTo: function(state, children) { + var views = this.views; + for (var i = 0, l = views.length; i < l; i++) { + views[i].transitionTo(state, children); + } + }, + + push: function() { + this.length += arguments.length; + var views = this.views; + return views.push.apply(views, arguments); + }, + + objectAt: function(idx) { + return this.views[idx]; + }, + + forEach: function(callback) { + var views = this.views; + return a_forEach(views, callback); + }, + + clear: function() { + this.length = 0; + this.views.length = 0; + } +}; + +var EMPTY_ARRAY = []; + +/** + `Ember.View` is the class in Ember responsible for encapsulating templates of + HTML content, combining templates with data to render as sections of a page's + DOM, and registering and responding to user-initiated events. + + ## HTML Tag + + The default HTML tag name used for a view's DOM representation is `div`. This + can be customized by setting the `tagName` property. The following view + class: + + ```javascript + ParagraphView = Ember.View.extend({ + tagName: 'em' + }); + ``` + + Would result in instances with the following HTML: + + ```html + + ``` + + ## HTML `class` Attribute + + The HTML `class` attribute of a view's tag can be set by providing a + `classNames` property that is set to an array of strings: + + ```javascript + MyView = Ember.View.extend({ + classNames: ['my-class', 'my-other-class'] + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html +
            + ``` + + `class` attribute values can also be set by providing a `classNameBindings` + property set to an array of properties names for the view. The return value + of these properties will be added as part of the value for the view's `class` + attribute. These properties can be computed properties: + + ```javascript + MyView = Ember.View.extend({ + classNameBindings: ['propertyA', 'propertyB'], + propertyA: 'from-a', + propertyB: function() { + if (someLogic) { return 'from-b'; } + }.property() + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html +
            + ``` + + If the value of a class name binding returns a boolean the property name + itself will be used as the class name if the property is true. The class name + will not be added if the value is `false` or `undefined`. + + ```javascript + MyView = Ember.View.extend({ + classNameBindings: ['hovered'], + hovered: true + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html +
            + ``` + + When using boolean class name bindings you can supply a string value other + than the property name for use as the `class` HTML attribute by appending the + preferred value after a ":" character when defining the binding: + + ```javascript + MyView = Ember.View.extend({ + classNameBindings: ['awesome:so-very-cool'], + awesome: true + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html +
            + ``` + + Boolean value class name bindings whose property names are in a + camelCase-style format will be converted to a dasherized format: + + ```javascript + MyView = Ember.View.extend({ + classNameBindings: ['isUrgent'], + isUrgent: true + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html +
            + ``` + + Class name bindings can also refer to object values that are found by + traversing a path relative to the view itself: + + ```javascript + MyView = Ember.View.extend({ + classNameBindings: ['messages.empty'] + messages: Ember.Object.create({ + empty: true + }) + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html +
            + ``` + + If you want to add a class name for a property which evaluates to true and + and a different class name if it evaluates to false, you can pass a binding + like this: + + ```javascript + // Applies 'enabled' class when isEnabled is true and 'disabled' when isEnabled is false + Ember.View.extend({ + classNameBindings: ['isEnabled:enabled:disabled'] + isEnabled: true + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html +
            + ``` + + When isEnabled is `false`, the resulting HTML reprensentation looks like + this: + + ```html +
            + ``` + + This syntax offers the convenience to add a class if a property is `false`: + + ```javascript + // Applies no class when isEnabled is true and class 'disabled' when isEnabled is false + Ember.View.extend({ + classNameBindings: ['isEnabled::disabled'] + isEnabled: true + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html +
            + ``` + + When the `isEnabled` property on the view is set to `false`, it will result + in view instances with an HTML representation of: + + ```html +
            + ``` + + Updates to the the value of a class name binding will result in automatic + update of the HTML `class` attribute in the view's rendered HTML + representation. If the value becomes `false` or `undefined` the class name + will be removed. + + Both `classNames` and `classNameBindings` are concatenated properties. See + [Ember.Object](/api/classes/Ember.Object.html) documentation for more + information about concatenated properties. + + ## HTML Attributes + + The HTML attribute section of a view's tag can be set by providing an + `attributeBindings` property set to an array of property names on the view. + The return value of these properties will be used as the value of the view's + HTML associated attribute: + + ```javascript + AnchorView = Ember.View.extend({ + tagName: 'a', + attributeBindings: ['href'], + href: 'http://google.com' + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html + + ``` + + If the return value of an `attributeBindings` monitored property is a boolean + the property will follow HTML's pattern of repeating the attribute's name as + its value: + + ```javascript + MyTextInput = Ember.View.extend({ + tagName: 'input', + attributeBindings: ['disabled'], + disabled: true + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html + + ``` + + `attributeBindings` can refer to computed properties: + + ```javascript + MyTextInput = Ember.View.extend({ + tagName: 'input', + attributeBindings: ['disabled'], + disabled: function() { + if (someLogic) { + return true; + } else { + return false; + } + }.property() + }); + ``` + + Updates to the the property of an attribute binding will result in automatic + update of the HTML attribute in the view's rendered HTML representation. + + `attributeBindings` is a concatenated property. See [Ember.Object](/api/classes/Ember.Object.html) + documentation for more information about concatenated properties. + + ## Templates + + The HTML contents of a view's rendered representation are determined by its + template. Templates can be any function that accepts an optional context + parameter and returns a string of HTML that will be inserted within the + view's tag. Most typically in Ember this function will be a compiled + `Ember.Handlebars` template. + + ```javascript + AView = Ember.View.extend({ + template: Ember.Handlebars.compile('I am the template') + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html +
            I am the template
            + ``` + + Within an Ember application is more common to define a Handlebars templates as + part of a page: + + ```html + + ``` + + And associate it by name using a view's `templateName` property: + + ```javascript + AView = Ember.View.extend({ + templateName: 'some-template' + }); + ``` + + Using a value for `templateName` that does not have a Handlebars template + with a matching `data-template-name` attribute will throw an error. + + For views classes that may have a template later defined (e.g. as the block + portion of a `{{view}}` Handlebars helper call in another template or in + a subclass), you can provide a `defaultTemplate` property set to compiled + template function. If a template is not later provided for the view instance + the `defaultTemplate` value will be used: + + ```javascript + AView = Ember.View.extend({ + defaultTemplate: Ember.Handlebars.compile('I was the default'), + template: null, + templateName: null + }); + ``` + + Will result in instances with an HTML representation of: + + ```html +
            I was the default
            + ``` + + If a `template` or `templateName` is provided it will take precedence over + `defaultTemplate`: + + ```javascript + AView = Ember.View.extend({ + defaultTemplate: Ember.Handlebars.compile('I was the default') + }); + + aView = AView.create({ + template: Ember.Handlebars.compile('I was the template, not default') + }); + ``` + + Will result in the following HTML representation when rendered: + + ```html +
            I was the template, not default
            + ``` + + ## View Context + + The default context of the compiled template is the view's controller: + + ```javascript + AView = Ember.View.extend({ + template: Ember.Handlebars.compile('Hello {{excitedGreeting}}') + }); + + aController = Ember.Object.create({ + firstName: 'Barry', + excitedGreeting: function() { + return this.get("content.firstName") + "!!!" + }.property() + }); + + aView = AView.create({ + controller: aController, + }); + ``` + + Will result in an HTML representation of: + + ```html +
            Hello Barry!!!
            + ``` + + A context can also be explicitly supplied through the view's `context` + property. If the view has neither `context` nor `controller` properties, the + `parentView`'s context will be used. + + ## Layouts + + Views can have a secondary template that wraps their main template. Like + primary templates, layouts can be any function that accepts an optional + context parameter and returns a string of HTML that will be inserted inside + view's tag. Views whose HTML element is self closing (e.g. ``) + cannot have a layout and this property will be ignored. + + Most typically in Ember a layout will be a compiled `Ember.Handlebars` + template. + + A view's layout can be set directly with the `layout` property or reference + an existing Handlebars template by name with the `layoutName` property. + + A template used as a layout must contain a single use of the Handlebars + `{{yield}}` helper. The HTML contents of a view's rendered `template` will be + inserted at this location: + + ```javascript + AViewWithLayout = Ember.View.extend({ + layout: Ember.Handlebars.compile("
            {{yield}}
            ") + template: Ember.Handlebars.compile("I got wrapped"), + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html +
            +
            + I got wrapped +
            +
            + ``` + + See [Ember.Handlebars.helpers.yield](/api/classes/Ember.Handlebars.helpers.html#method_yield) + for more information. + + ## Responding to Browser Events + + Views can respond to user-initiated events in one of three ways: method + implementation, through an event manager, and through `{{action}}` helper use + in their template or layout. + + ### Method Implementation + + Views can respond to user-initiated events by implementing a method that + matches the event name. A `jQuery.Event` object will be passed as the + argument to this method. + + ```javascript + AView = Ember.View.extend({ + click: function(event) { + // will be called when when an instance's + // rendered element is clicked + } + }); + ``` + + ### Event Managers + + Views can define an object as their `eventManager` property. This object can + then implement methods that match the desired event names. Matching events + that occur on the view's rendered HTML or the rendered HTML of any of its DOM + descendants will trigger this method. A `jQuery.Event` object will be passed + as the first argument to the method and an `Ember.View` object as the + second. The `Ember.View` will be the view whose rendered HTML was interacted + with. This may be the view with the `eventManager` property or one of its + descendent views. + + ```javascript + AView = Ember.View.extend({ + eventManager: Ember.Object.create({ + doubleClick: function(event, view) { + // will be called when when an instance's + // rendered element or any rendering + // of this views's descendent + // elements is clicked + } + }) + }); + ``` + + An event defined for an event manager takes precedence over events of the + same name handled through methods on the view. + + ```javascript + AView = Ember.View.extend({ + mouseEnter: function(event) { + // will never trigger. + }, + eventManager: Ember.Object.create({ + mouseEnter: function(event, view) { + // takes precedence over AView#mouseEnter + } + }) + }); + ``` + + Similarly a view's event manager will take precedence for events of any views + rendered as a descendent. A method name that matches an event name will not + be called if the view instance was rendered inside the HTML representation of + a view that has an `eventManager` property defined that handles events of the + name. Events not handled by the event manager will still trigger method calls + on the descendent. + + ```javascript + OuterView = Ember.View.extend({ + template: Ember.Handlebars.compile("outer {{#view InnerView}}inner{{/view}} outer"), + eventManager: Ember.Object.create({ + mouseEnter: function(event, view) { + // view might be instance of either + // OuterView or InnerView depending on + // where on the page the user interaction occured + } + }) + }); + + InnerView = Ember.View.extend({ + click: function(event) { + // will be called if rendered inside + // an OuterView because OuterView's + // eventManager doesn't handle click events + }, + mouseEnter: function(event) { + // will never be called if rendered inside + // an OuterView. + } + }); + ``` + + ### Handlebars `{{action}}` Helper + + See [Handlebars.helpers.action](/api/classes/Ember.Handlebars.helpers.html#method_action). + + ### Event Names + + All of the event handling approaches described above respond to the same set + of events. The names of the built-in events are listed below. (The hash of + built-in events exists in `Ember.EventDispatcher`.) Additional, custom events + can be registered by using `Ember.Application.customEvents`. + + Touch events: + + * `touchStart` + * `touchMove` + * `touchEnd` + * `touchCancel` + + Keyboard events + + * `keyDown` + * `keyUp` + * `keyPress` + + Mouse events + + * `mouseDown` + * `mouseUp` + * `contextMenu` + * `click` + * `doubleClick` + * `mouseMove` + * `focusIn` + * `focusOut` + * `mouseEnter` + * `mouseLeave` + + Form events: + + * `submit` + * `change` + * `focusIn` + * `focusOut` + * `input` + + HTML5 drag and drop events: + + * `dragStart` + * `drag` + * `dragEnter` + * `dragLeave` + * `drop` + * `dragEnd` + + ## Handlebars `{{view}}` Helper + + Other `Ember.View` instances can be included as part of a view's template by + using the `{{view}}` Handlebars helper. See [Ember.Handlebars.helpers.view](/api/classes/Ember.Handlebars.helpers.html#method_view) + for additional information. + + @class View + @namespace Ember + @extends Ember.CoreView +*/ +Ember.View = Ember.CoreView.extend( +/** @scope Ember.View.prototype */ { + + concatenatedProperties: ['classNames', 'classNameBindings', 'attributeBindings'], + + /** + @property isView + @type Boolean + @default true + @final + */ + isView: true, + + // .......................................................... + // TEMPLATE SUPPORT + // + + /** + The name of the template to lookup if no template is provided. + + By default `Ember.View` will lookup a template with this name in + `Ember.TEMPLATES` (a shared global object). + + @property templateName + @type String + @default null + */ + templateName: null, + + /** + The name of the layout to lookup if no layout is provided. + + By default `Ember.View` will lookup a template with this name in + `Ember.TEMPLATES` (a shared global object). + + @property layoutName + @type String + @default null + */ + layoutName: null, + + /** + The template used to render the view. This should be a function that + accepts an optional context parameter and returns a string of HTML that + will be inserted into the DOM relative to its parent view. + + In general, you should set the `templateName` property instead of setting + the template yourself. + + @property template + @type Function + */ + template: Ember.computed(function(key, value) { + if (value !== undefined) { return value; } + + var templateName = get(this, 'templateName'), + template = this.templateForName(templateName, 'template'); + + Ember.assert("You specified the templateName " + templateName + " for " + this + ", but it did not exist.", !templateName || template); + + return template || get(this, 'defaultTemplate'); + }).property('templateName'), + + /** + The controller managing this view. If this property is set, it will be + made available for use by the template. + + @property controller + @type Object + */ + controller: Ember.computed(function(key) { + var parentView = get(this, '_parentView'); + return parentView ? get(parentView, 'controller') : null; + }).property('_parentView'), + + /** + A view may contain a layout. A layout is a regular template but + supersedes the `template` property during rendering. It is the + responsibility of the layout template to retrieve the `template` + property from the view (or alternatively, call `Handlebars.helpers.yield`, + `{{yield}}`) to render it in the correct location. + + This is useful for a view that has a shared wrapper, but which delegates + the rendering of the contents of the wrapper to the `template` property + on a subclass. + + @property layout + @type Function + */ + layout: Ember.computed(function(key) { + var layoutName = get(this, 'layoutName'), + layout = this.templateForName(layoutName, 'layout'); + + Ember.assert("You specified the layoutName " + layoutName + " for " + this + ", but it did not exist.", !layoutName || layout); + + return layout || get(this, 'defaultLayout'); + }).property('layoutName'), + + _yield: function(context, options) { + var template = get(this, 'template'); + if (template) { template(context, options); } + }, + + templateForName: function(name, type) { + if (!name) { return; } + Ember.assert("templateNames are not allowed to contain periods: "+name, name.indexOf('.') === -1); + + // the defaultContainer is deprecated + var container = this.container || (Ember.Container && Ember.Container.defaultContainer); + return container && container.lookup('template:' + name); + }, + + /** + The object from which templates should access properties. + + This object will be passed to the template function each time the render + method is called, but it is up to the individual function to decide what + to do with it. + + By default, this will be the view's controller. + + @property context + @type Object + */ + context: Ember.computed(function(key, value) { + if (arguments.length === 2) { + set(this, '_context', value); + return value; + } else { + return get(this, '_context'); + } + }).volatile(), + + /** + @private + + Private copy of the view's template context. This can be set directly + by Handlebars without triggering the observer that causes the view + to be re-rendered. + + The context of a view is looked up as follows: + + 1. Supplied context (usually by Handlebars) + 2. Specified controller + 3. `parentView`'s context (for a child of a ContainerView) + + The code in Handlebars that overrides the `_context` property first + checks to see whether the view has a specified controller. This is + something of a hack and should be revisited. + + @property _context + */ + _context: Ember.computed(function(key) { + var parentView, controller; + + if (controller = get(this, 'controller')) { + return controller; + } + + parentView = this._parentView; + if (parentView) { + return get(parentView, '_context'); + } + + return null; + }), + + /** + @private + + If a value that affects template rendering changes, the view should be + re-rendered to reflect the new value. + + @method _contextDidChange + */ + _contextDidChange: Ember.observer('context', function() { + this.rerender(); + }), + + /** + If `false`, the view will appear hidden in DOM. + + @property isVisible + @type Boolean + @default null + */ + isVisible: true, + + /** + @private + + Array of child views. You should never edit this array directly. + Instead, use `appendChild` and `removeFromParent`. + + @property childViews + @type Array + @default [] + */ + childViews: childViewsProperty, + + _childViews: EMPTY_ARRAY, + + // When it's a virtual view, we need to notify the parent that their + // childViews will change. + _childViewsWillChange: Ember.beforeObserver('childViews', function() { + if (this.isVirtual) { + var parentView = get(this, 'parentView'); + if (parentView) { Ember.propertyWillChange(parentView, 'childViews'); } + } + }), + + // When it's a virtual view, we need to notify the parent that their + // childViews did change. + _childViewsDidChange: Ember.observer('childViews', function() { + if (this.isVirtual) { + var parentView = get(this, 'parentView'); + if (parentView) { Ember.propertyDidChange(parentView, 'childViews'); } + } + }), + + /** + Return the nearest ancestor that is an instance of the provided + class. + + @property nearestInstanceOf + @param {Class} klass Subclass of Ember.View (or Ember.View itself) + @return Ember.View + @deprecated + */ + nearestInstanceOf: function(klass) { + Ember.deprecate("nearestInstanceOf is deprecated and will be removed from future releases. Use nearestOfType."); + var view = get(this, 'parentView'); + + while (view) { + if (view instanceof klass) { return view; } + view = get(view, 'parentView'); + } + }, + + /** + Return the nearest ancestor that is an instance of the provided + class or mixin. + + @property nearestOfType + @param {Class,Mixin} klass Subclass of Ember.View (or Ember.View itself), + or an instance of Ember.Mixin. + @return Ember.View + */ + nearestOfType: function(klass) { + var view = get(this, 'parentView'), + isOfType = klass instanceof Ember.Mixin ? + function(view) { return klass.detect(view); } : + function(view) { return klass.detect(view.constructor); }; + + while (view) { + if (isOfType(view)) { return view; } + view = get(view, 'parentView'); + } + }, + + /** + Return the nearest ancestor that has a given property. + + @property nearestWithProperty + @param {String} property A property name + @return Ember.View + */ + nearestWithProperty: function(property) { + var view = get(this, 'parentView'); + + while (view) { + if (property in view) { return view; } + view = get(view, 'parentView'); + } + }, + + /** + Return the nearest ancestor whose parent is an instance of + `klass`. + + @property nearestChildOf + @param {Class} klass Subclass of Ember.View (or Ember.View itself) + @return Ember.View + */ + nearestChildOf: function(klass) { + var view = get(this, 'parentView'); + + while (view) { + if (get(view, 'parentView') instanceof klass) { return view; } + view = get(view, 'parentView'); + } + }, + + /** + @private + + When the parent view changes, recursively invalidate `controller` + + @method _parentViewDidChange + */ + _parentViewDidChange: Ember.observer('_parentView', function() { + if (this.isDestroying) { return; } + + this.trigger('parentViewDidChange'); + + if (get(this, 'parentView.controller') && !get(this, 'controller')) { + this.notifyPropertyChange('controller'); + } + }), + + _controllerDidChange: Ember.observer('controller', function() { + if (this.isDestroying) { return; } + + this.rerender(); + + this.forEachChildView(function(view) { + view.propertyDidChange('controller'); + }); + }), + + cloneKeywords: function() { + var templateData = get(this, 'templateData'); + + var keywords = templateData ? Ember.copy(templateData.keywords) : {}; + set(keywords, 'view', get(this, 'concreteView')); + set(keywords, '_view', this); + set(keywords, 'controller', get(this, 'controller')); + + return keywords; + }, + + /** + Called on your view when it should push strings of HTML into a + `Ember.RenderBuffer`. Most users will want to override the `template` + or `templateName` properties instead of this method. + + By default, `Ember.View` will look for a function in the `template` + property and invoke it with the value of `context`. The value of + `context` will be the view's controller unless you override it. + + @method render + @param {Ember.RenderBuffer} buffer The render buffer + */ + render: function(buffer) { + // If this view has a layout, it is the responsibility of the + // the layout to render the view's template. Otherwise, render the template + // directly. + var template = get(this, 'layout') || get(this, 'template'); + + if (template) { + var context = get(this, 'context'); + var keywords = this.cloneKeywords(); + var output; + + var data = { + view: this, + buffer: buffer, + isRenderData: true, + keywords: keywords, + insideGroup: get(this, 'templateData.insideGroup') + }; + + // Invoke the template with the provided template context, which + // is the view's controller by default. A hash of data is also passed that provides + // the template with access to the view and render buffer. + + Ember.assert('template must be a function. Did you mean to call Ember.Handlebars.compile("...") or specify templateName instead?', typeof template === 'function'); + // The template should write directly to the render buffer instead + // of returning a string. + output = template(context, { data: data }); + + // If the template returned a string instead of writing to the buffer, + // push the string onto the buffer. + if (output !== undefined) { buffer.push(output); } + } + }, + + /** + Renders the view again. This will work regardless of whether the + view is already in the DOM or not. If the view is in the DOM, the + rendering process will be deferred to give bindings a chance + to synchronize. + + If children were added during the rendering process using `appendChild`, + `rerender` will remove them, because they will be added again + if needed by the next `render`. + + In general, if the display of your view changes, you should modify + the DOM element directly instead of manually calling `rerender`, which can + be slow. + + @method rerender + */ + rerender: function() { + return this.currentState.rerender(this); + }, + + clearRenderedChildren: function() { + var lengthBefore = this.lengthBeforeRender, + lengthAfter = this.lengthAfterRender; + + // If there were child views created during the last call to render(), + // remove them under the assumption that they will be re-created when + // we re-render. + + // VIEW-TODO: Unit test this path. + var childViews = this._childViews; + for (var i=lengthAfter-1; i>=lengthBefore; i--) { + if (childViews[i]) { childViews[i].destroy(); } + } + }, + + /** + @private + + Iterates over the view's `classNameBindings` array, inserts the value + of the specified property into the `classNames` array, then creates an + observer to update the view's element if the bound property ever changes + in the future. + + @method _applyClassNameBindings + */ + _applyClassNameBindings: function(classBindings) { + var classNames = this.classNames, + elem, newClass, dasherizedClass; + + // Loop through all of the configured bindings. These will be either + // property names ('isUrgent') or property paths relative to the view + // ('content.isUrgent') + a_forEach(classBindings, function(binding) { + + // Variable in which the old class value is saved. The observer function + // closes over this variable, so it knows which string to remove when + // the property changes. + var oldClass; + // Extract just the property name from bindings like 'foo:bar' + var parsedPath = Ember.View._parsePropertyPath(binding); + + // Set up an observer on the context. If the property changes, toggle the + // class name. + var observer = function() { + // Get the current value of the property + newClass = this._classStringForProperty(binding); + elem = this.$(); + + // If we had previously added a class to the element, remove it. + if (oldClass) { + elem.removeClass(oldClass); + // Also remove from classNames so that if the view gets rerendered, + // the class doesn't get added back to the DOM. + classNames.removeObject(oldClass); + } + + // If necessary, add a new class. Make sure we keep track of it so + // it can be removed in the future. + if (newClass) { + elem.addClass(newClass); + oldClass = newClass; + } else { + oldClass = null; + } + }; + + // Get the class name for the property at its current value + dasherizedClass = this._classStringForProperty(binding); + + if (dasherizedClass) { + // Ensure that it gets into the classNames array + // so it is displayed when we render. + a_addObject(classNames, dasherizedClass); + + // Save a reference to the class name so we can remove it + // if the observer fires. Remember that this variable has + // been closed over by the observer. + oldClass = dasherizedClass; + } + + this.registerObserver(this, parsedPath.path, observer); + // Remove className so when the view is rerendered, + // the className is added based on binding reevaluation + this.one('willClearRender', function() { + if (oldClass) { + classNames.removeObject(oldClass); + oldClass = null; + } + }); + + }, this); + }, + + /** + @private + + Iterates through the view's attribute bindings, sets up observers for each, + then applies the current value of the attributes to the passed render buffer. + + @method _applyAttributeBindings + @param {Ember.RenderBuffer} buffer + */ + _applyAttributeBindings: function(buffer, attributeBindings) { + var attributeValue, elem; + + a_forEach(attributeBindings, function(binding) { + var split = binding.split(':'), + property = split[0], + attributeName = split[1] || property; + + // Create an observer to add/remove/change the attribute if the + // JavaScript property changes. + var observer = function() { + elem = this.$(); + + attributeValue = get(this, property); + + Ember.View.applyAttributeBindings(elem, attributeName, attributeValue); + }; + + this.registerObserver(this, property, observer); + + // Determine the current value and add it to the render buffer + // if necessary. + attributeValue = get(this, property); + Ember.View.applyAttributeBindings(buffer, attributeName, attributeValue); + }, this); + }, + + /** + @private + + Given a property name, returns a dasherized version of that + property name if the property evaluates to a non-falsy value. + + For example, if the view has property `isUrgent` that evaluates to true, + passing `isUrgent` to this method will return `"is-urgent"`. + + @method _classStringForProperty + @param property + */ + _classStringForProperty: function(property) { + var parsedPath = Ember.View._parsePropertyPath(property); + var path = parsedPath.path; + + var val = get(this, path); + if (val === undefined && Ember.isGlobalPath(path)) { + val = get(Ember.lookup, path); + } + + return Ember.View._classStringForValue(path, val, parsedPath.className, parsedPath.falsyClassName); + }, + + // .......................................................... + // ELEMENT SUPPORT + // + + /** + Returns the current DOM element for the view. + + @property element + @type DOMElement + */ + element: Ember.computed(function(key, value) { + if (value !== undefined) { + return this.currentState.setElement(this, value); + } else { + return this.currentState.getElement(this); + } + }).property('_parentView'), + + /** + Returns a jQuery object for this view's element. If you pass in a selector + string, this method will return a jQuery object, using the current element + as its buffer. + + For example, calling `view.$('li')` will return a jQuery object containing + all of the `li` elements inside the DOM element of this view. + + @method $ + @param {String} [selector] a jQuery-compatible selector string + @return {jQuery} the jQuery object for the DOM node + */ + $: function(sel) { + return this.currentState.$(this, sel); + }, + + mutateChildViews: function(callback) { + var childViews = this._childViews, + idx = childViews.length, + view; + + while(--idx >= 0) { + view = childViews[idx]; + callback(this, view, idx); + } + + return this; + }, + + forEachChildView: function(callback) { + var childViews = this._childViews; + + if (!childViews) { return this; } + + var len = childViews.length, + view, idx; + + for (idx = 0; idx < len; idx++) { + view = childViews[idx]; + callback(view); + } + + return this; + }, + + /** + Appends the view's element to the specified parent element. + + If the view does not have an HTML representation yet, `createElement()` + will be called automatically. + + Note that this method just schedules the view to be appended; the DOM + element will not be appended to the given element until all bindings have + finished synchronizing. + + This is not typically a function that you will need to call directly when + building your application. You might consider using `Ember.ContainerView` + instead. If you do need to use `appendTo`, be sure that the target element + you are providing is associated with an `Ember.Application` and does not + have an ancestor element that is associated with an Ember view. + + @method appendTo + @param {String|DOMElement|jQuery} A selector, element, HTML string, or jQuery object + @return {Ember.View} receiver + */ + appendTo: function(target) { + // Schedule the DOM element to be created and appended to the given + // element after bindings have synchronized. + this._insertElementLater(function() { + Ember.assert("You tried to append to (" + target + ") but that isn't in the DOM", Ember.$(target).length > 0); + Ember.assert("You cannot append to an existing Ember.View. Consider using Ember.ContainerView instead.", !Ember.$(target).is('.ember-view') && !Ember.$(target).parents().is('.ember-view')); + this.$().appendTo(target); + }); + + return this; + }, + + /** + Replaces the content of the specified parent element with this view's + element. If the view does not have an HTML representation yet, + `createElement()` will be called automatically. + + Note that this method just schedules the view to be appended; the DOM + element will not be appended to the given element until all bindings have + finished synchronizing + + @method replaceIn + @param {String|DOMElement|jQuery} A selector, element, HTML string, or jQuery object + @return {Ember.View} received + */ + replaceIn: function(target) { + Ember.assert("You tried to replace in (" + target + ") but that isn't in the DOM", Ember.$(target).length > 0); + Ember.assert("You cannot replace an existing Ember.View. Consider using Ember.ContainerView instead.", !Ember.$(target).is('.ember-view') && !Ember.$(target).parents().is('.ember-view')); + + this._insertElementLater(function() { + Ember.$(target).empty(); + this.$().appendTo(target); + }); + + return this; + }, + + /** + @private + + Schedules a DOM operation to occur during the next render phase. This + ensures that all bindings have finished synchronizing before the view is + rendered. + + To use, pass a function that performs a DOM operation. + + Before your function is called, this view and all child views will receive + the `willInsertElement` event. After your function is invoked, this view + and all of its child views will receive the `didInsertElement` event. + + ```javascript + view._insertElementLater(function() { + this.createElement(); + this.$().appendTo('body'); + }); + ``` + + @method _insertElementLater + @param {Function} fn the function that inserts the element into the DOM + */ + _insertElementLater: function(fn) { + this._scheduledInsert = Ember.run.scheduleOnce('render', this, '_insertElement', fn); + }, + + _insertElement: function (fn) { + this._scheduledInsert = null; + this.currentState.insertElement(this, fn); + }, + + /** + Appends the view's element to the document body. If the view does + not have an HTML representation yet, `createElement()` will be called + automatically. + + If your application uses the `rootElement` property, you must append + the view within that element. Rendering views outside of the `rootElement` + is not supported. + + Note that this method just schedules the view to be appended; the DOM + element will not be appended to the document body until all bindings have + finished synchronizing. + + @method append + @return {Ember.View} receiver + */ + append: function() { + return this.appendTo(document.body); + }, + + /** + Removes the view's element from the element to which it is attached. + + @method remove + @return {Ember.View} receiver + */ + remove: function() { + // What we should really do here is wait until the end of the run loop + // to determine if the element has been re-appended to a different + // element. + // In the interim, we will just re-render if that happens. It is more + // important than elements get garbage collected. + if (!this.removedFromDOM) { this.destroyElement(); } + this.invokeRecursively(function(view) { + if (view.clearRenderedChildren) { view.clearRenderedChildren(); } + }); + }, + + elementId: null, + + /** + Attempts to discover the element in the parent element. The default + implementation looks for an element with an ID of `elementId` (or the + view's guid if `elementId` is null). You can override this method to + provide your own form of lookup. For example, if you want to discover your + element using a CSS class name instead of an ID. + + @method findElementInParentElement + @param {DOMElement} parentElement The parent's DOM element + @return {DOMElement} The discovered element + */ + findElementInParentElement: function(parentElem) { + var id = "#" + this.elementId; + return Ember.$(id)[0] || Ember.$(id, parentElem)[0]; + }, + + /** + Creates a DOM representation of the view and all of its + child views by recursively calling the `render()` method. + + After the element has been created, `didInsertElement` will + be called on this view and all of its child views. + + @method createElement + @return {Ember.View} receiver + */ + createElement: function() { + if (get(this, 'element')) { return this; } + + var buffer = this.renderToBuffer(); + set(this, 'element', buffer.element()); + + return this; + }, + + /** + Called when a view is going to insert an element into the DOM. + + @event willInsertElement + */ + willInsertElement: Ember.K, + + /** + Called when the element of the view has been inserted into the DOM + or after the view was re-rendered. Override this function to do any + set up that requires an element in the document body. + + @event didInsertElement + */ + didInsertElement: Ember.K, + + /** + Called when the view is about to rerender, but before anything has + been torn down. This is a good opportunity to tear down any manual + observers you have installed based on the DOM state + + @event willClearRender + */ + willClearRender: Ember.K, + + /** + @private + + Run this callback on the current view (unless includeSelf is false) and recursively on child views. + + @method invokeRecursively + @param fn {Function} + @param includeSelf (optional, default true) + */ + invokeRecursively: function(fn, includeSelf) { + var childViews = (includeSelf === false) ? this._childViews : [this]; + var currentViews, view, currentChildViews; + + while (childViews.length) { + currentViews = childViews.slice(); + childViews = []; + + for (var i=0, l=currentViews.length; i` tag for views. + + @property tagName + @type String + @default null + */ + + // We leave this null by default so we can tell the difference between + // the default case and a user-specified tag. + tagName: null, + + /** + The WAI-ARIA role of the control represented by this view. For example, a + button may have a role of type 'button', or a pane may have a role of + type 'alertdialog'. This property is used by assistive software to help + visually challenged users navigate rich web applications. + + The full list of valid WAI-ARIA roles is available at: + [http://www.w3.org/TR/wai-aria/roles#roles_categorization](http://www.w3.org/TR/wai-aria/roles#roles_categorization) + + @property ariaRole + @type String + @default null + */ + ariaRole: null, + + /** + Standard CSS class names to apply to the view's outer element. This + property automatically inherits any class names defined by the view's + superclasses as well. + + @property classNames + @type Array + @default ['ember-view'] + */ + classNames: ['ember-view'], + + /** + A list of properties of the view to apply as class names. If the property + is a string value, the value of that string will be applied as a class + name. + + ```javascript + // Applies the 'high' class to the view element + Ember.View.extend({ + classNameBindings: ['priority'] + priority: 'high' + }); + ``` + + If the value of the property is a Boolean, the name of that property is + added as a dasherized class name. + + ```javascript + // Applies the 'is-urgent' class to the view element + Ember.View.extend({ + classNameBindings: ['isUrgent'] + isUrgent: true + }); + ``` + + If you would prefer to use a custom value instead of the dasherized + property name, you can pass a binding like this: + + ```javascript + // Applies the 'urgent' class to the view element + Ember.View.extend({ + classNameBindings: ['isUrgent:urgent'] + isUrgent: true + }); + ``` + + This list of properties is inherited from the view's superclasses as well. + + @property classNameBindings + @type Array + @default [] + */ + classNameBindings: EMPTY_ARRAY, + + /** + A list of properties of the view to apply as attributes. If the property is + a string value, the value of that string will be applied as the attribute. + + ```javascript + // Applies the type attribute to the element + // with the value "button", like
            + Ember.View.extend({ + attributeBindings: ['type'], + type: 'button' + }); + ``` + + If the value of the property is a Boolean, the name of that property is + added as an attribute. + + ```javascript + // Renders something like
            + Ember.View.extend({ + attributeBindings: ['enabled'], + enabled: true + }); + ``` + + @property attributeBindings + */ + attributeBindings: EMPTY_ARRAY, + + // ....................................................... + // CORE DISPLAY METHODS + // + + /** + @private + + Setup a view, but do not finish waking it up. + - configure `childViews` + - register the view with the global views hash, which is used for event + dispatch + + @method init + */ + init: function() { + this.elementId = this.elementId || guidFor(this); + + this._super(); + + // setup child views. be sure to clone the child views array first + this._childViews = this._childViews.slice(); + + Ember.assert("Only arrays are allowed for 'classNameBindings'", Ember.typeOf(this.classNameBindings) === 'array'); + this.classNameBindings = Ember.A(this.classNameBindings.slice()); + + Ember.assert("Only arrays are allowed for 'classNames'", Ember.typeOf(this.classNames) === 'array'); + this.classNames = Ember.A(this.classNames.slice()); + }, + + appendChild: function(view, options) { + return this.currentState.appendChild(this, view, options); + }, + + /** + Removes the child view from the parent view. + + @method removeChild + @param {Ember.View} view + @return {Ember.View} receiver + */ + removeChild: function(view) { + // If we're destroying, the entire subtree will be + // freed, and the DOM will be handled separately, + // so no need to mess with childViews. + if (this.isDestroying) { return; } + + // update parent node + set(view, '_parentView', null); + + // remove view from childViews array. + var childViews = this._childViews; + + Ember.EnumerableUtils.removeObject(childViews, view); + + this.propertyDidChange('childViews'); // HUH?! what happened to will change? + + return this; + }, + + /** + Removes all children from the `parentView`. + + @method removeAllChildren + @return {Ember.View} receiver + */ + removeAllChildren: function() { + return this.mutateChildViews(function(parentView, view) { + parentView.removeChild(view); + }); + }, + + destroyAllChildren: function() { + return this.mutateChildViews(function(parentView, view) { + view.destroy(); + }); + }, + + /** + Removes the view from its `parentView`, if one is found. Otherwise + does nothing. + + @method removeFromParent + @return {Ember.View} receiver + */ + removeFromParent: function() { + var parent = this._parentView; + + // Remove DOM element from parent + this.remove(); + + if (parent) { parent.removeChild(this); } + return this; + }, + + /** + You must call `destroy` on a view to destroy the view (and all of its + child views). This will remove the view from any parent node, then make + sure that the DOM element managed by the view can be released by the + memory manager. + + @method destroy + */ + destroy: function() { + var childViews = this._childViews, + // get parentView before calling super because it'll be destroyed + nonVirtualParentView = get(this, 'parentView'), + viewName = this.viewName, + childLen, i; + + if (!this._super()) { return; } + + childLen = childViews.length; + for (i=childLen-1; i>=0; i--) { + childViews[i].removedFromDOM = true; + } + + // remove from non-virtual parent view if viewName was specified + if (viewName && nonVirtualParentView) { + nonVirtualParentView.set(viewName, null); + } + + childLen = childViews.length; + for (i=childLen-1; i>=0; i--) { + childViews[i].destroy(); + } + + return this; + }, + + /** + Instantiates a view to be added to the childViews array during view + initialization. You generally will not call this method directly unless + you are overriding `createChildViews()`. Note that this method will + automatically configure the correct settings on the new view instance to + act as a child of the parent. + + @method createChildView + @param {Class|String} viewClass + @param {Hash} [attrs] Attributes to add + @return {Ember.View} new instance + */ + createChildView: function(view, attrs) { + if (!view) { + throw new TypeError("createChildViews first argument must exist"); + } + + if (view.isView && view._parentView === this && view.container === this.container) { + return view; + } + + attrs = attrs || {}; + attrs._parentView = this; + + if (Ember.CoreView.detect(view)) { + attrs.templateData = attrs.templateData || get(this, 'templateData'); + + attrs.container = this.container; + view = view.create(attrs); + + // don't set the property on a virtual view, as they are invisible to + // consumers of the view API + if (view.viewName) { + set(get(this, 'concreteView'), view.viewName, view); + } + } else if ('string' === typeof view) { + var fullName = 'view:' + view; + var View = this.container.lookupFactory(fullName); + + Ember.assert("Could not find view: '" + fullName + "'", !!View); + + attrs.templateData = get(this, 'templateData'); + view = View.create(attrs); + } else { + Ember.assert('You must pass instance or subclass of View', view.isView); + attrs.container = this.container; + + if (!get(view, 'templateData')) { + attrs.templateData = get(this, 'templateData'); + } + + Ember.setProperties(view, attrs); + + } + + return view; + }, + + becameVisible: Ember.K, + becameHidden: Ember.K, + + /** + @private + + When the view's `isVisible` property changes, toggle the visibility + element of the actual DOM element. + + @method _isVisibleDidChange + */ + _isVisibleDidChange: Ember.observer('isVisible', function() { + var $el = this.$(); + if (!$el) { return; } + + var isVisible = get(this, 'isVisible'); + + $el.toggle(isVisible); + + if (this._isAncestorHidden()) { return; } + + if (isVisible) { + this._notifyBecameVisible(); + } else { + this._notifyBecameHidden(); + } + }), + + _notifyBecameVisible: function() { + this.trigger('becameVisible'); + + this.forEachChildView(function(view) { + var isVisible = get(view, 'isVisible'); + + if (isVisible || isVisible === null) { + view._notifyBecameVisible(); + } + }); + }, + + _notifyBecameHidden: function() { + this.trigger('becameHidden'); + this.forEachChildView(function(view) { + var isVisible = get(view, 'isVisible'); + + if (isVisible || isVisible === null) { + view._notifyBecameHidden(); + } + }); + }, + + _isAncestorHidden: function() { + var parent = get(this, 'parentView'); + + while (parent) { + if (get(parent, 'isVisible') === false) { return true; } + + parent = get(parent, 'parentView'); + } + + return false; + }, + + clearBuffer: function() { + this.invokeRecursively(function(view) { + view.buffer = null; + }); + }, + + transitionTo: function(state, children) { + var priorState = this.currentState, + currentState = this.currentState = this.states[state]; + this.state = state; + + if (priorState && priorState.exit) { priorState.exit(this); } + if (currentState.enter) { currentState.enter(this); } + if (state === 'inDOM') { delete Ember.meta(this).cache.element; } + + if (children !== false) { + this.forEachChildView(function(view) { + view.transitionTo(state); + }); + } + }, + + // ....................................................... + // EVENT HANDLING + // + + /** + @private + + Handle events from `Ember.EventDispatcher` + + @method handleEvent + @param eventName {String} + @param evt {Event} + */ + handleEvent: function(eventName, evt) { + return this.currentState.handleEvent(this, eventName, evt); + }, + + registerObserver: function(root, path, target, observer) { + if (!observer && 'function' === typeof target) { + observer = target; + target = null; + } + + if (!root || typeof root !== 'object') { + return; + } + + var view = this, + stateCheckedObserver = function() { + view.currentState.invokeObserver(this, observer); + }, + scheduledObserver = function() { + Ember.run.scheduleOnce('render', this, stateCheckedObserver); + }; + + Ember.addObserver(root, path, target, scheduledObserver); + + this.one('willClearRender', function() { + Ember.removeObserver(root, path, target, scheduledObserver); + }); + } + +}); + +/* + Describe how the specified actions should behave in the various + states that a view can exist in. Possible states: + + * preRender: when a view is first instantiated, and after its + element was destroyed, it is in the preRender state + * inBuffer: once a view has been rendered, but before it has + been inserted into the DOM, it is in the inBuffer state + * inDOM: once a view has been inserted into the DOM it is in + the inDOM state. A view spends the vast majority of its + existence in this state. + * destroyed: once a view has been destroyed (using the destroy + method), it is in this state. No further actions can be invoked + on a destroyed view. +*/ + + // in the destroyed state, everything is illegal + + // before rendering has begun, all legal manipulations are noops. + + // inside the buffer, legal manipulations are done on the buffer + + // once the view has been inserted into the DOM, legal manipulations + // are done on the DOM element. + +function notifyMutationListeners() { + Ember.run.once(Ember.View, 'notifyMutationListeners'); +} + +var DOMManager = { + prepend: function(view, html) { + view.$().prepend(html); + notifyMutationListeners(); + }, + + after: function(view, html) { + view.$().after(html); + notifyMutationListeners(); + }, + + html: function(view, html) { + view.$().html(html); + notifyMutationListeners(); + }, + + replace: function(view) { + var element = get(view, 'element'); + + set(view, 'element', null); + + view._insertElementLater(function() { + Ember.$(element).replaceWith(get(view, 'element')); + notifyMutationListeners(); + }); + }, + + remove: function(view) { + view.$().remove(); + notifyMutationListeners(); + }, + + empty: function(view) { + view.$().empty(); + notifyMutationListeners(); + } +}; + +Ember.View.reopen({ + domManager: DOMManager +}); + +Ember.View.reopenClass({ + + /** + @private + + Parse a path and return an object which holds the parsed properties. + + For example a path like "content.isEnabled:enabled:disabled" will return the + following object: + + ```javascript + { + path: "content.isEnabled", + className: "enabled", + falsyClassName: "disabled", + classNames: ":enabled:disabled" + } + ``` + + @method _parsePropertyPath + @static + */ + _parsePropertyPath: function(path) { + var split = path.split(':'), + propertyPath = split[0], + classNames = "", + className, + falsyClassName; + + // check if the property is defined as prop:class or prop:trueClass:falseClass + if (split.length > 1) { + className = split[1]; + if (split.length === 3) { falsyClassName = split[2]; } + + classNames = ':' + className; + if (falsyClassName) { classNames += ":" + falsyClassName; } + } + + return { + path: propertyPath, + classNames: classNames, + className: (className === '') ? undefined : className, + falsyClassName: falsyClassName + }; + }, + + /** + @private + + Get the class name for a given value, based on the path, optional + `className` and optional `falsyClassName`. + + - if a `className` or `falsyClassName` has been specified: + - if the value is truthy and `className` has been specified, + `className` is returned + - if the value is falsy and `falsyClassName` has been specified, + `falsyClassName` is returned + - otherwise `null` is returned + - if the value is `true`, the dasherized last part of the supplied path + is returned + - if the value is not `false`, `undefined` or `null`, the `value` + is returned + - if none of the above rules apply, `null` is returned + + @method _classStringForValue + @param path + @param val + @param className + @param falsyClassName + @static + */ + _classStringForValue: function(path, val, className, falsyClassName) { + // When using the colon syntax, evaluate the truthiness or falsiness + // of the value to determine which className to return + if (className || falsyClassName) { + if (className && !!val) { + return className; + + } else if (falsyClassName && !val) { + return falsyClassName; + + } else { + return null; + } + + // If value is a Boolean and true, return the dasherized property + // name. + } else if (val === true) { + // Normalize property path to be suitable for use + // as a class name. For exaple, content.foo.barBaz + // becomes bar-baz. + var parts = path.split('.'); + return Ember.String.dasherize(parts[parts.length-1]); + + // If the value is not false, undefined, or null, return the current + // value of the property. + } else if (val !== false && val != null) { + return val; + + // Nothing to display. Return null so that the old class is removed + // but no new class is added. + } else { + return null; + } + } +}); + +var mutation = Ember.Object.extend(Ember.Evented).create(); + +Ember.View.addMutationListener = function(callback) { + mutation.on('change', callback); +}; + +Ember.View.removeMutationListener = function(callback) { + mutation.off('change', callback); +}; + +Ember.View.notifyMutationListeners = function() { + mutation.trigger('change'); +}; + +/** + Global views hash + + @property views + @static + @type Hash +*/ +Ember.View.views = {}; + +// If someone overrides the child views computed property when +// defining their class, we want to be able to process the user's +// supplied childViews and then restore the original computed property +// at view initialization time. This happens in Ember.ContainerView's init +// method. +Ember.View.childViewsProperty = childViewsProperty; + +Ember.View.applyAttributeBindings = function(elem, name, value) { + var type = Ember.typeOf(value); + + // if this changes, also change the logic in ember-handlebars/lib/helpers/binding.js + if (name !== 'value' && (type === 'string' || (type === 'number' && !isNaN(value)))) { + if (value !== elem.attr(name)) { + elem.attr(name, value); + } + } else if (name === 'value' || type === 'boolean') { + // We can't set properties to undefined or null + if (Ember.isNone(value)) { value = ''; } + + if (value !== elem.prop(name)) { + // value and booleans should always be properties + elem.prop(name, value); + } + } else if (!value) { + elem.removeAttr(name); + } +}; + +Ember.View.states = states; + +})(); + + + +(function() { +/** +@module ember +@submodule ember-views +*/ + +var get = Ember.get, set = Ember.set; + +Ember.View.states._default = { + // appendChild is only legal while rendering the buffer. + appendChild: function() { + throw "You can't use appendChild outside of the rendering process"; + }, + + $: function() { + return undefined; + }, + + getElement: function() { + return null; + }, + + // Handle events from `Ember.EventDispatcher` + handleEvent: function() { + return true; // continue event propagation + }, + + destroyElement: function(view) { + set(view, 'element', null); + if (view._scheduledInsert) { + Ember.run.cancel(view._scheduledInsert); + view._scheduledInsert = null; + } + return view; + }, + + renderToBufferIfNeeded: function () { + return false; + }, + + rerender: Ember.K, + invokeObserver: Ember.K +}; + +})(); + + + +(function() { +/** +@module ember +@submodule ember-views +*/ + +var preRender = Ember.View.states.preRender = Ember.create(Ember.View.states._default); + +Ember.merge(preRender, { + // a view leaves the preRender state once its element has been + // created (createElement). + insertElement: function(view, fn) { + view.createElement(); + var viewCollection = view.viewHierarchyCollection(); + + viewCollection.trigger('willInsertElement'); + + fn.call(view); + + // We transition to `inDOM` if the element exists in the DOM + var element = view.get('element'); + while (element = element.parentNode) { + if (element === document) { + viewCollection.transitionTo('inDOM', false); + viewCollection.trigger('didInsertElement'); + } + } + + }, + + renderToBufferIfNeeded: function(view, buffer) { + view.renderToBuffer(buffer); + return true; + }, + + empty: Ember.K, + + setElement: function(view, value) { + if (value !== null) { + view.transitionTo('hasElement'); + } + return value; + } +}); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-views +*/ + +var get = Ember.get, set = Ember.set; + +var inBuffer = Ember.View.states.inBuffer = Ember.create(Ember.View.states._default); + +Ember.merge(inBuffer, { + $: function(view, sel) { + // if we don't have an element yet, someone calling this.$() is + // trying to update an element that isn't in the DOM. Instead, + // rerender the view to allow the render method to reflect the + // changes. + view.rerender(); + return Ember.$(); + }, + + // when a view is rendered in a buffer, rerendering it simply + // replaces the existing buffer with a new one + rerender: function(view) { + throw new Ember.Error("Something you did caused a view to re-render after it rendered but before it was inserted into the DOM."); + }, + + // when a view is rendered in a buffer, appending a child + // view will render that view and append the resulting + // buffer into its buffer. + appendChild: function(view, childView, options) { + var buffer = view.buffer, _childViews = view._childViews; + + childView = view.createChildView(childView, options); + if (!_childViews.length) { _childViews = view._childViews = _childViews.slice(); } + _childViews.push(childView); + + childView.renderToBuffer(buffer); + + view.propertyDidChange('childViews'); + + return childView; + }, + + // when a view is rendered in a buffer, destroying the + // element will simply destroy the buffer and put the + // state back into the preRender state. + destroyElement: function(view) { + view.clearBuffer(); + var viewCollection = view._notifyWillDestroyElement(); + viewCollection.transitionTo('preRender', false); + + return view; + }, + + empty: function() { + Ember.assert("Emptying a view in the inBuffer state is not allowed and should not happen under normal circumstances. Most likely there is a bug in your application. This may be due to excessive property change notifications."); + }, + + renderToBufferIfNeeded: function (view, buffer) { + return false; + }, + + // It should be impossible for a rendered view to be scheduled for + // insertion. + insertElement: function() { + throw "You can't insert an element that has already been rendered"; + }, + + setElement: function(view, value) { + if (value === null) { + view.transitionTo('preRender'); + } else { + view.clearBuffer(); + view.transitionTo('hasElement'); + } + + return value; + }, + + invokeObserver: function(target, observer) { + observer.call(target); + } +}); + + +})(); + + + +(function() { +/** +@module ember +@submodule ember-views +*/ + +var get = Ember.get, set = Ember.set; + +var hasElement = Ember.View.states.hasElement = Ember.create(Ember.View.states._default); + +Ember.merge(hasElement, { + $: function(view, sel) { + var elem = get(view, 'element'); + return sel ? Ember.$(sel, elem) : Ember.$(elem); + }, + + getElement: function(view) { + var parent = get(view, 'parentView'); + if (parent) { parent = get(parent, 'element'); } + if (parent) { return view.findElementInParentElement(parent); } + return Ember.$("#" + get(view, 'elementId'))[0]; + }, + + setElement: function(view, value) { + if (value === null) { + view.transitionTo('preRender'); + } else { + throw "You cannot set an element to a non-null value when the element is already in the DOM."; + } + + return value; + }, + + // once the view has been inserted into the DOM, rerendering is + // deferred to allow bindings to synchronize. + rerender: function(view) { + view.triggerRecursively('willClearRender'); + + view.clearRenderedChildren(); + + view.domManager.replace(view); + return view; + }, + + // once the view is already in the DOM, destroying it removes it + // from the DOM, nukes its element, and puts it back into the + // preRender state if inDOM. + + destroyElement: function(view) { + view._notifyWillDestroyElement(); + view.domManager.remove(view); + set(view, 'element', null); + if (view._scheduledInsert) { + Ember.run.cancel(view._scheduledInsert); + view._scheduledInsert = null; + } + return view; + }, + + empty: function(view) { + var _childViews = view._childViews, len, idx; + if (_childViews) { + len = _childViews.length; + for (idx = 0; idx < len; idx++) { + _childViews[idx]._notifyWillDestroyElement(); + } + } + view.domManager.empty(view); + }, + + // Handle events from `Ember.EventDispatcher` + handleEvent: function(view, eventName, evt) { + if (view.has(eventName)) { + // Handler should be able to re-dispatch events, so we don't + // preventDefault or stopPropagation. + return view.trigger(eventName, evt); + } else { + return true; // continue event propagation + } + }, + + invokeObserver: function(target, observer) { + observer.call(target); + } +}); + +var inDOM = Ember.View.states.inDOM = Ember.create(hasElement); + +Ember.merge(inDOM, { + enter: function(view) { + // Register the view for event handling. This hash is used by + // Ember.EventDispatcher to dispatch incoming events. + if (!view.isVirtual) { + Ember.assert("Attempted to register a view with an id already in use: "+view.elementId, !Ember.View.views[view.elementId]); + Ember.View.views[view.elementId] = view; + } + + view.addBeforeObserver('elementId', function() { + throw new Ember.Error("Changing a view's elementId after creation is not allowed"); + }); + }, + + exit: function(view) { + if (!this.isVirtual) delete Ember.View.views[view.elementId]; + }, + + insertElement: function(view, fn) { + throw "You can't insert an element into the DOM that has already been inserted"; + } +}); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-views +*/ + +var destroyingError = "You can't call %@ on a view being destroyed", fmt = Ember.String.fmt; + +var destroying = Ember.View.states.destroying = Ember.create(Ember.View.states._default); + +Ember.merge(destroying, { + appendChild: function() { + throw fmt(destroyingError, ['appendChild']); + }, + rerender: function() { + throw fmt(destroyingError, ['rerender']); + }, + destroyElement: function() { + throw fmt(destroyingError, ['destroyElement']); + }, + empty: function() { + throw fmt(destroyingError, ['empty']); + }, + + setElement: function() { + throw fmt(destroyingError, ["set('element', ...)"]); + }, + + renderToBufferIfNeeded: function() { + return false; + }, + + // Since element insertion is scheduled, don't do anything if + // the view has been destroyed between scheduling and execution + insertElement: Ember.K +}); + + +})(); + + + +(function() { +Ember.View.cloneStates = function(from) { + var into = {}; + + into._default = {}; + into.preRender = Ember.create(into._default); + into.destroying = Ember.create(into._default); + into.inBuffer = Ember.create(into._default); + into.hasElement = Ember.create(into._default); + into.inDOM = Ember.create(into.hasElement); + + for (var stateName in from) { + if (!from.hasOwnProperty(stateName)) { continue; } + Ember.merge(into[stateName], from[stateName]); + } + + return into; +}; + +})(); + + + +(function() { +var states = Ember.View.cloneStates(Ember.View.states); + +/** +@module ember +@submodule ember-views +*/ + +var get = Ember.get, set = Ember.set; +var forEach = Ember.EnumerableUtils.forEach; +var ViewCollection = Ember._ViewCollection; + +/** + A `ContainerView` is an `Ember.View` subclass that implements `Ember.MutableArray` + allowing programatic management of its child views. + + ## Setting Initial Child Views + + The initial array of child views can be set in one of two ways. You can + provide a `childViews` property at creation time that contains instance of + `Ember.View`: + + ```javascript + aContainer = Ember.ContainerView.create({ + childViews: [Ember.View.create(), Ember.View.create()] + }); + ``` + + You can also provide a list of property names whose values are instances of + `Ember.View`: + + ```javascript + aContainer = Ember.ContainerView.create({ + childViews: ['aView', 'bView', 'cView'], + aView: Ember.View.create(), + bView: Ember.View.create(), + cView: Ember.View.create() + }); + ``` + + The two strategies can be combined: + + ```javascript + aContainer = Ember.ContainerView.create({ + childViews: ['aView', Ember.View.create()], + aView: Ember.View.create() + }); + ``` + + Each child view's rendering will be inserted into the container's rendered + HTML in the same order as its position in the `childViews` property. + + ## Adding and Removing Child Views + + The container view implements `Ember.MutableArray` allowing programatic management of its child views. + + To remove a view, pass that view into a `removeObject` call on the container view. + + Given an empty `` the following code + + ```javascript + aContainer = Ember.ContainerView.create({ + classNames: ['the-container'], + childViews: ['aView', 'bView'], + aView: Ember.View.create({ + template: Ember.Handlebars.compile("A") + }), + bView: Ember.View.create({ + template: Ember.Handlebars.compile("B") + }) + }); + + aContainer.appendTo('body'); + ``` + + Results in the HTML + + ```html +
            +
            A
            +
            B
            +
            + ``` + + Removing a view + + ```javascript + aContainer.toArray(); // [aContainer.aView, aContainer.bView] + aContainer.removeObject(aContainer.get('bView')); + aContainer.toArray(); // [aContainer.aView] + ``` + + Will result in the following HTML + + ```html +
            +
            A
            +
            + ``` + + Similarly, adding a child view is accomplished by adding `Ember.View` instances to the + container view. + + Given an empty `` the following code + + ```javascript + aContainer = Ember.ContainerView.create({ + classNames: ['the-container'], + childViews: ['aView', 'bView'], + aView: Ember.View.create({ + template: Ember.Handlebars.compile("A") + }), + bView: Ember.View.create({ + template: Ember.Handlebars.compile("B") + }) + }); + + aContainer.appendTo('body'); + ``` + + Results in the HTML + + ```html +
            +
            A
            +
            B
            +
            + ``` + + Adding a view + + ```javascript + AnotherViewClass = Ember.View.extend({ + template: Ember.Handlebars.compile("Another view") + }); + + aContainer.toArray(); // [aContainer.aView, aContainer.bView] + aContainer.pushObject(AnotherViewClass.create()); + aContainer.toArray(); // [aContainer.aView, aContainer.bView, ] + ``` + + Will result in the following HTML + + ```html +
            +
            A
            +
            B
            +
            Another view
            +
            + ``` + + ## Templates and Layout + + A `template`, `templateName`, `defaultTemplate`, `layout`, `layoutName` or + `defaultLayout` property on a container view will not result in the template + or layout being rendered. The HTML contents of a `Ember.ContainerView`'s DOM + representation will only be the rendered HTML of its child views. + + @class ContainerView + @namespace Ember + @extends Ember.View +*/ +Ember.ContainerView = Ember.View.extend(Ember.MutableArray, { + states: states, + + init: function() { + this._super(); + + var childViews = get(this, 'childViews'); + + // redefine view's childViews property that was obliterated + Ember.defineProperty(this, 'childViews', Ember.View.childViewsProperty); + + var _childViews = this._childViews; + + forEach(childViews, function(viewName, idx) { + var view; + + if ('string' === typeof viewName) { + view = get(this, viewName); + view = this.createChildView(view); + set(this, viewName, view); + } else { + view = this.createChildView(viewName); + } + + _childViews[idx] = view; + }, this); + + var currentView = get(this, 'currentView'); + if (currentView) { + if (!_childViews.length) { _childViews = this._childViews = this._childViews.slice(); } + _childViews.push(this.createChildView(currentView)); + } + }, + + replace: function(idx, removedCount, addedViews) { + var addedCount = addedViews ? get(addedViews, 'length') : 0; + var self = this; + Ember.assert("You can't add a child to a container that is already a child of another view", Ember.A(addedViews).every(function(item) { return !get(item, '_parentView') || get(item, '_parentView') === self; })); + + this.arrayContentWillChange(idx, removedCount, addedCount); + this.childViewsWillChange(this._childViews, idx, removedCount); + + if (addedCount === 0) { + this._childViews.splice(idx, removedCount) ; + } else { + var args = [idx, removedCount].concat(addedViews); + if (addedViews.length && !this._childViews.length) { this._childViews = this._childViews.slice(); } + this._childViews.splice.apply(this._childViews, args); + } + + this.arrayContentDidChange(idx, removedCount, addedCount); + this.childViewsDidChange(this._childViews, idx, removedCount, addedCount); + + return this; + }, + + objectAt: function(idx) { + return this._childViews[idx]; + }, + + length: Ember.computed(function () { + return this._childViews.length; + }).volatile(), + + /** + @private + + Instructs each child view to render to the passed render buffer. + + @method render + @param {Ember.RenderBuffer} buffer the buffer to render to + */ + render: function(buffer) { + this.forEachChildView(function(view) { + view.renderToBuffer(buffer); + }); + }, + + instrumentName: 'container', + + /** + @private + + When a child view is removed, destroy its element so that + it is removed from the DOM. + + The array observer that triggers this action is set up in the + `renderToBuffer` method. + + @method childViewsWillChange + @param {Ember.Array} views the child views array before mutation + @param {Number} start the start position of the mutation + @param {Number} removed the number of child views removed + **/ + childViewsWillChange: function(views, start, removed) { + this.propertyWillChange('childViews'); + + if (removed > 0) { + var changedViews = views.slice(start, start+removed); + // transition to preRender before clearing parentView + this.currentState.childViewsWillChange(this, views, start, removed); + this.initializeViews(changedViews, null, null); + } + }, + + removeChild: function(child) { + this.removeObject(child); + return this; + }, + + /** + @private + + When a child view is added, make sure the DOM gets updated appropriately. + + If the view has already rendered an element, we tell the child view to + create an element and insert it into the DOM. If the enclosing container + view has already written to a buffer, but not yet converted that buffer + into an element, we insert the string representation of the child into the + appropriate place in the buffer. + + @method childViewsDidChange + @param {Ember.Array} views the array of child views afte the mutation has occurred + @param {Number} start the start position of the mutation + @param {Number} removed the number of child views removed + @param {Number} the number of child views added + */ + childViewsDidChange: function(views, start, removed, added) { + if (added > 0) { + var changedViews = views.slice(start, start+added); + this.initializeViews(changedViews, this, get(this, 'templateData')); + this.currentState.childViewsDidChange(this, views, start, added); + } + this.propertyDidChange('childViews'); + }, + + initializeViews: function(views, parentView, templateData) { + forEach(views, function(view) { + set(view, '_parentView', parentView); + + if (!view.container && parentView) { + set(view, 'container', parentView.container); + } + + if (!get(view, 'templateData')) { + set(view, 'templateData', templateData); + } + }); + }, + + currentView: null, + + _currentViewWillChange: Ember.beforeObserver('currentView', function() { + var currentView = get(this, 'currentView'); + if (currentView) { + currentView.destroy(); + } + }), + + _currentViewDidChange: Ember.observer('currentView', function() { + var currentView = get(this, 'currentView'); + if (currentView) { + Ember.assert("You tried to set a current view that already has a parent. Make sure you don't have multiple outlets in the same view.", !get(currentView, '_parentView')); + this.pushObject(currentView); + } + }), + + _ensureChildrenAreInDOM: function () { + this.currentState.ensureChildrenAreInDOM(this); + } +}); + +Ember.merge(states._default, { + childViewsWillChange: Ember.K, + childViewsDidChange: Ember.K, + ensureChildrenAreInDOM: Ember.K +}); + +Ember.merge(states.inBuffer, { + childViewsDidChange: function(parentView, views, start, added) { + throw new Ember.Error('You cannot modify child views while in the inBuffer state'); + } +}); + +Ember.merge(states.hasElement, { + childViewsWillChange: function(view, views, start, removed) { + for (var i=start; i` and the following code: + + ```javascript + someItemsView = Ember.CollectionView.create({ + classNames: ['a-collection'], + content: ['A','B','C'], + itemViewClass: Ember.View.extend({ + template: Ember.Handlebars.compile("the letter: {{view.content}}") + }) + }); + + someItemsView.appendTo('body'); + ``` + + Will result in the following HTML structure + + ```html +
            +
            the letter: A
            +
            the letter: B
            +
            the letter: C
            +
            + ``` + + ## Automatic matching of parent/child tagNames + + Setting the `tagName` property of a `CollectionView` to any of + "ul", "ol", "table", "thead", "tbody", "tfoot", "tr", or "select" will result + in the item views receiving an appropriately matched `tagName` property. + + Given an empty `` and the following code: + + ```javascript + anUndorderedListView = Ember.CollectionView.create({ + tagName: 'ul', + content: ['A','B','C'], + itemViewClass: Ember.View.extend({ + template: Ember.Handlebars.compile("the letter: {{view.content}}") + }) + }); + + anUndorderedListView.appendTo('body'); + ``` + + Will result in the following HTML structure + + ```html +
              +
            • the letter: A
            • +
            • the letter: B
            • +
            • the letter: C
            • +
            + ``` + + Additional `tagName` pairs can be provided by adding to + `Ember.CollectionView.CONTAINER_MAP ` + + ```javascript + Ember.CollectionView.CONTAINER_MAP['article'] = 'section' + ``` + + ## Programatic creation of child views + + For cases where additional customization beyond the use of a single + `itemViewClass` or `tagName` matching is required CollectionView's + `createChildView` method can be overidden: + + ```javascript + CustomCollectionView = Ember.CollectionView.extend({ + createChildView: function(viewClass, attrs) { + if (attrs.content.kind == 'album') { + viewClass = App.AlbumView; + } else { + viewClass = App.SongView; + } + return this._super(viewClass, attrs); + } + }); + ``` + + ## Empty View + + You can provide an `Ember.View` subclass to the `Ember.CollectionView` + instance as its `emptyView` property. If the `content` property of a + `CollectionView` is set to `null` or an empty array, an instance of this view + will be the `CollectionView`s only child. + + ```javascript + aListWithNothing = Ember.CollectionView.create({ + classNames: ['nothing'] + content: null, + emptyView: Ember.View.extend({ + template: Ember.Handlebars.compile("The collection is empty") + }) + }); + + aListWithNothing.appendTo('body'); + ``` + + Will result in the following HTML structure + + ```html +
            +
            + The collection is empty +
            +
            + ``` + + ## Adding and Removing items + + The `childViews` property of a `CollectionView` should not be directly + manipulated. Instead, add, remove, replace items from its `content` property. + This will trigger appropriate changes to its rendered HTML. + + + @class CollectionView + @namespace Ember + @extends Ember.ContainerView + @since Ember 0.9 +*/ +Ember.CollectionView = Ember.ContainerView.extend(/** @scope Ember.CollectionView.prototype */ { + + /** + A list of items to be displayed by the `Ember.CollectionView`. + + @property content + @type Ember.Array + @default null + */ + content: null, + + /** + @private + + This provides metadata about what kind of empty view class this + collection would like if it is being instantiated from another + system (like Handlebars) + + @property emptyViewClass + */ + emptyViewClass: Ember.View, + + /** + An optional view to display if content is set to an empty array. + + @property emptyView + @type Ember.View + @default null + */ + emptyView: null, + + /** + @property itemViewClass + @type Ember.View + @default Ember.View + */ + itemViewClass: Ember.View, + + /** + Setup a CollectionView + + @method init + */ + init: function() { + var ret = this._super(); + this._contentDidChange(); + return ret; + }, + + /** + @private + + Invoked when the content property is about to change. Notifies observers that the + entire array content will change. + + @method _contentWillChange + */ + _contentWillChange: Ember.beforeObserver('content', function() { + var content = this.get('content'); + + if (content) { content.removeArrayObserver(this); } + var len = content ? get(content, 'length') : 0; + this.arrayWillChange(content, 0, len); + }), + + /** + @private + + Check to make sure that the content has changed, and if so, + update the children directly. This is always scheduled + asynchronously, to allow the element to be created before + bindings have synchronized and vice versa. + + @method _contentDidChange + */ + _contentDidChange: Ember.observer('content', function() { + var content = get(this, 'content'); + + if (content) { + this._assertArrayLike(content); + content.addArrayObserver(this); + } + + var len = content ? get(content, 'length') : 0; + this.arrayDidChange(content, 0, null, len); + }), + + /** + @private + + Ensure that the content implements Ember.Array + + @method _assertArrayLike + */ + _assertArrayLike: function(content) { + Ember.assert(fmt("an Ember.CollectionView's content must implement Ember.Array. You passed %@", [content]), Ember.Array.detect(content)); + }, + + /** + Removes the content and content observers. + + @method destroy + */ + destroy: function() { + if (!this._super()) { return; } + + var content = get(this, 'content'); + if (content) { content.removeArrayObserver(this); } + + if (this._createdEmptyView) { + this._createdEmptyView.destroy(); + } + + return this; + }, + + /** + Called when a mutation to the underlying content array will occur. + + This method will remove any views that are no longer in the underlying + content array. + + Invokes whenever the content array itself will change. + + @method arrayWillChange + @param {Array} content the managed collection of objects + @param {Number} start the index at which the changes will occurr + @param {Number} removed number of object to be removed from content + */ + arrayWillChange: function(content, start, removedCount) { + // If the contents were empty before and this template collection has an + // empty view remove it now. + var emptyView = get(this, 'emptyView'); + if (emptyView && emptyView instanceof Ember.View) { + emptyView.removeFromParent(); + } + + // Loop through child views that correspond with the removed items. + // Note that we loop from the end of the array to the beginning because + // we are mutating it as we go. + var childViews = this._childViews, childView, idx, len; + + len = this._childViews.length; + + var removingAll = removedCount === len; + + if (removingAll) { + this.currentState.empty(this); + this.invokeRecursively(function(view) { + view.removedFromDOM = true; + }, false); + } + + for (idx = start + removedCount - 1; idx >= start; idx--) { + childView = childViews[idx]; + childView.destroy(); + } + }, + + /** + Called when a mutation to the underlying content array occurs. + + This method will replay that mutation against the views that compose the + `Ember.CollectionView`, ensuring that the view reflects the model. + + This array observer is added in `contentDidChange`. + + @method arrayDidChange + @param {Array} content the managed collection of objects + @param {Number} start the index at which the changes occurred + @param {Number} removed number of object removed from content + @param {Number} added number of object added to content + */ + arrayDidChange: function(content, start, removed, added) { + var addedViews = [], view, item, idx, len, itemViewClass, + emptyView; + + len = content ? get(content, 'length') : 0; + + if (len) { + itemViewClass = get(this, 'itemViewClass'); + + if ('string' === typeof itemViewClass) { + itemViewClass = get(itemViewClass) || itemViewClass; + } + + Ember.assert(fmt("itemViewClass must be a subclass of Ember.View, not %@", [itemViewClass]), 'string' === typeof itemViewClass || Ember.View.detect(itemViewClass)); + + for (idx = start; idx < start+added; idx++) { + item = content.objectAt(idx); + + view = this.createChildView(itemViewClass, { + content: item, + contentIndex: idx + }); + + addedViews.push(view); + } + } else { + emptyView = get(this, 'emptyView'); + + if (!emptyView) { return; } + + if ('string' === typeof emptyView) { + emptyView = get(emptyView) || emptyView; + } + + emptyView = this.createChildView(emptyView); + addedViews.push(emptyView); + set(this, 'emptyView', emptyView); + + if (Ember.CoreView.detect(emptyView)) { + this._createdEmptyView = emptyView; + } + } + + this.replace(start, 0, addedViews); + }, + + /** + Instantiates a view to be added to the childViews array during view + initialization. You generally will not call this method directly unless + you are overriding `createChildViews()`. Note that this method will + automatically configure the correct settings on the new view instance to + act as a child of the parent. + + The tag name for the view will be set to the tagName of the viewClass + passed in. + + @method createChildView + @param {Class} viewClass + @param {Hash} [attrs] Attributes to add + @return {Ember.View} new instance + */ + createChildView: function(view, attrs) { + view = this._super(view, attrs); + + var itemTagName = get(view, 'tagName'); + + if (itemTagName === null || itemTagName === undefined) { + itemTagName = Ember.CollectionView.CONTAINER_MAP[get(this, 'tagName')]; + set(view, 'tagName', itemTagName); + } + + return view; + } +}); + +/** + A map of parent tags to their default child tags. You can add + additional parent tags if you want collection views that use + a particular parent tag to default to a child tag. + + @property CONTAINER_MAP + @type Hash + @static + @final +*/ +Ember.CollectionView.CONTAINER_MAP = { + ul: 'li', + ol: 'li', + table: 'tr', + thead: 'tr', + tbody: 'tr', + tfoot: 'tr', + tr: 'td', + select: 'option' +}; + +})(); + + + +(function() { +var get = Ember.get, set = Ember.set, isNone = Ember.isNone, + a_slice = Array.prototype.slice; + + +/** +@module ember +@submodule ember-views +*/ + +/** + An `Ember.Component` is a view that is completely + isolated. Property access in its templates go + to the view object and actions are targeted at + the view object. There is no access to the + surrounding context or outer controller; all + contextual information is passed in. + + The easiest way to create an `Ember.Component` is via + a template. If you name a template + `components/my-foo`, you will be able to use + `{{my-foo}}` in other templates, which will make + an instance of the isolated component. + + ```html + {{app-profile person=currentUser}} + ``` + + ```html + +

            {{person.title}}

            + +

            {{person.signature}}

            + ``` + + You can also use `yield` inside a template to + include the **contents** of the custom tag: + + ```html + {{#app-profile person=currentUser}} +

            Admin mode

            + {{/app-profile}} + ``` + + ```html + +

            {{person.title}}

            + {{yield}} + ``` + + If you want to customize the component, in order to + handle events or actions, you implement a subclass + of `Ember.Component` named after the name of the + component. Note that `Component` needs to be appended to the name of + your subclass like `AppProfileComponent`. + + For example, you could implement the action + `hello` for the `app-profile` component: + + ```javascript + App.AppProfileComponent = Ember.Component.extend({ + actions: { + hello: function(name) { + console.log("Hello", name); + } + } + }); + ``` + + And then use it in the component's template: + + ```html + + +

            {{person.title}}

            + {{yield}} + + + ``` + + Components must have a `-` in their name to avoid + conflicts with built-in controls that wrap HTML + elements. This is consistent with the same + requirement in web components. + + @class Component + @namespace Ember + @extends Ember.View +*/ +Ember.Component = Ember.View.extend(Ember.TargetActionSupport, { + init: function() { + this._super(); + set(this, 'context', this); + set(this, 'controller', this); + }, + + // during render, isolate keywords + cloneKeywords: function() { + return { + view: this, + controller: this + }; + }, + + _yield: function(context, options) { + var view = options.data.view, + parentView = this._parentView, + template = get(this, 'template'); + + if (template) { + Ember.assert("A Component must have a parent view in order to yield.", parentView); + + view.appendChild(Ember.View, { + isVirtual: true, + tagName: '', + _contextView: parentView, + template: template, + context: get(parentView, 'context'), + controller: get(parentView, 'controller'), + templateData: { keywords: parentView.cloneKeywords() } + }); + } + }, + + /** + If the component is currently inserted into the DOM of a parent view, this + property will point to the controller of the parent view. + + @property targetObject + @type Ember.Controller + @default null + */ + targetObject: Ember.computed(function(key) { + var parentView = get(this, '_parentView'); + return parentView ? get(parentView, 'controller') : null; + }).property('_parentView'), + + /** + Triggers a named action on the controller context where the component is used if + this controller has registered for notifications of the action. + + For example a component for playing or pausing music may translate click events + into action notifications of "play" or "stop" depending on some internal state + of the component: + + + ```javascript + App.PlayButtonComponent = Ember.Component.extend({ + click: function(){ + if (this.get('isPlaying')) { + this.triggerAction('play'); + } else { + this.triggerAction('stop'); + } + } + }); + ``` + + When used inside a template these component actions are configured to + trigger actions in the outer application context: + + ```handlebars + {{! application.hbs }} + {{play-button play="musicStarted" stop="musicStopped"}} + ``` + + When the component receives a browser `click` event it translate this + interaction into application-specific semantics ("play" or "stop") and + triggers the specified action name on the controller for the template + where the component is used: + + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + actions: { + musicStarted: function(){ + // called when the play button is clicked + // and the music started playing + }, + musicStopped: function(){ + // called when the play button is clicked + // and the music stopped playing + } + } + }); + ``` + + If no action name is passed to `sendAction` a default name of "action" + is assumed. + + ```javascript + App.NextButtonComponent = Ember.Component.extend({ + click: function(){ + this.sendAction(); + } + }); + ``` + + ```handlebars + {{! application.hbs }} + {{next-button action="playNextSongInAlbum"}} + ``` + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + actions: { + playNextSongInAlbum: function(){ + ... + } + } + }); + ``` + + @method sendAction + @param [action] {String} the action to trigger + @param [context] {*} a context to send with the action + */ + sendAction: function(action) { + var actionName, + contexts = a_slice.call(arguments, 1); + + // Send the default action + if (action === undefined) { + actionName = get(this, 'action'); + Ember.assert("The default action was triggered on the component " + this.toString() + ", but the action name (" + actionName + ") was not a string.", isNone(actionName) || typeof actionName === 'string'); + } else { + actionName = get(this, action); + Ember.assert("The " + action + " action was triggered on the component " + this.toString() + ", but the action name (" + actionName + ") was not a string.", isNone(actionName) || typeof actionName === 'string'); + } + + // If no action name for that action could be found, just abort. + if (actionName === undefined) { return; } + + this.triggerAction({ + action: actionName, + actionContext: contexts + }); + } +}); + +})(); + + + +(function() { + +})(); + + + +(function() { +/** +`Ember.ViewTargetActionSupport` is a mixin that can be included in a +view class to add a `triggerAction` method with semantics similar to +the Handlebars `{{action}}` helper. It provides intelligent defaults +for the action's target: the view's controller; and the context that is +sent with the action: the view's context. + +Note: In normal Ember usage, the `{{action}}` helper is usually the best +choice. This mixin is most often useful when you are doing more complex +event handling in custom View subclasses. + +For example: + +```javascript +App.SaveButtonView = Ember.View.extend(Ember.ViewTargetActionSupport, { + action: 'save', + click: function() { + this.triggerAction(); // Sends the `save` action, along with the current context + // to the current controller + } +}); +``` + +The `action` can be provided as properties of an optional object argument +to `triggerAction` as well. + +```javascript +App.SaveButtonView = Ember.View.extend(Ember.ViewTargetActionSupport, { + click: function() { + this.triggerAction({ + action: 'save' + }); // Sends the `save` action, along with the current context + // to the current controller + } +}); +``` + +@class ViewTargetActionSupport +@namespace Ember +@extends Ember.TargetActionSupport +*/ +Ember.ViewTargetActionSupport = Ember.Mixin.create(Ember.TargetActionSupport, { + /** + @property target + */ + target: Ember.computed.alias('controller'), + /** + @property actionContext + */ + actionContext: Ember.computed.alias('context') +}); + +})(); + + + +(function() { + +})(); + + + +(function() { +/** +Ember Views + +@module ember +@submodule ember-views +@requires ember-runtime +@main ember-views +*/ + +})(); + +(function() { +define("metamorph", + [], + function() { + "use strict"; + // ========================================================================== + // Project: metamorph + // Copyright: ©2011 My Company Inc. All rights reserved. + // ========================================================================== + + var K = function() {}, + guid = 0, + document = this.document, + disableRange = ('undefined' === typeof ENV ? {} : ENV).DISABLE_RANGE_API, + + // Feature-detect the W3C range API, the extended check is for IE9 which only partially supports ranges + supportsRange = (!disableRange) && document && ('createRange' in document) && (typeof Range !== 'undefined') && Range.prototype.createContextualFragment, + + // Internet Explorer prior to 9 does not allow setting innerHTML if the first element + // is a "zero-scope" element. This problem can be worked around by making + // the first node an invisible text node. We, like Modernizr, use ­ + needsShy = document && (function() { + var testEl = document.createElement('div'); + testEl.innerHTML = "
            "; + testEl.firstChild.innerHTML = ""; + return testEl.firstChild.innerHTML === ''; + })(), + + + // IE 8 (and likely earlier) likes to move whitespace preceeding + // a script tag to appear after it. This means that we can + // accidentally remove whitespace when updating a morph. + movesWhitespace = document && (function() { + var testEl = document.createElement('div'); + testEl.innerHTML = "Test: Value"; + return testEl.childNodes[0].nodeValue === 'Test:' && + testEl.childNodes[2].nodeValue === ' Value'; + })(); + + // Constructor that supports either Metamorph('foo') or new + // Metamorph('foo'); + // + // Takes a string of HTML as the argument. + + var Metamorph = function(html) { + var self; + + if (this instanceof Metamorph) { + self = this; + } else { + self = new K(); + } + + self.innerHTML = html; + var myGuid = 'metamorph-'+(guid++); + self.start = myGuid + '-start'; + self.end = myGuid + '-end'; + + return self; + }; + + K.prototype = Metamorph.prototype; + + var rangeFor, htmlFunc, removeFunc, outerHTMLFunc, appendToFunc, afterFunc, prependFunc, startTagFunc, endTagFunc; + + outerHTMLFunc = function() { + return this.startTag() + this.innerHTML + this.endTag(); + }; + + startTagFunc = function() { + /* + * We replace chevron by its hex code in order to prevent escaping problems. + * Check this thread for more explaination: + * http://stackoverflow.com/questions/8231048/why-use-x3c-instead-of-when-generating-html-from-javascript + */ + return "
    hi
    "; + * div.firstChild.firstChild.tagName //=> "" + * + * If our script markers are inside such a node, we need to find that + * node and use *it* as the marker. + */ + var realNode = function(start) { + while (start.parentNode.tagName === "") { + start = start.parentNode; + } + + return start; + }; + + /* + * When automatically adding a tbody, Internet Explorer inserts the + * tbody immediately before the first . Other browsers create it + * before the first node, no matter what. + * + * This means the the following code: + * + * div = document.createElement("div"); + * div.innerHTML = "
    hi
    + * + * Generates the following DOM in IE: + * + * + div + * + table + * - script id='first' + * + tbody + * + tr + * + td + * - "hi" + * - script id='last' + * + * Which means that the two script tags, even though they were + * inserted at the same point in the hierarchy in the original + * HTML, now have different parents. + * + * This code reparents the first script tag by making it the tbody's + * first child. + * + */ + var fixParentage = function(start, end) { + if (start.parentNode !== end.parentNode) { + end.parentNode.insertBefore(start, end.parentNode.firstChild); + } + }; + + htmlFunc = function(html, outerToo) { + // get the real starting node. see realNode for details. + var start = realNode(document.getElementById(this.start)); + var end = document.getElementById(this.end); + var parentNode = end.parentNode; + var node, nextSibling, last; + + // make sure that the start and end nodes share the same + // parent. If not, fix it. + fixParentage(start, end); + + // remove all of the nodes after the starting placeholder and + // before the ending placeholder. + node = start.nextSibling; + while (node) { + nextSibling = node.nextSibling; + last = node === end; + + // if this is the last node, and we want to remove it as well, + // set the `end` node to the next sibling. This is because + // for the rest of the function, we insert the new nodes + // before the end (note that insertBefore(node, null) is + // the same as appendChild(node)). + // + // if we do not want to remove it, just break. + if (last) { + if (outerToo) { end = node.nextSibling; } else { break; } + } + + node.parentNode.removeChild(node); + + // if this is the last node and we didn't break before + // (because we wanted to remove the outer nodes), break + // now. + if (last) { break; } + + node = nextSibling; + } + + // get the first node for the HTML string, even in cases like + // tables and lists where a simple innerHTML on a div would + // swallow some of the content. + node = firstNodeFor(start.parentNode, html); + + // copy the nodes for the HTML between the starting and ending + // placeholder. + while (node) { + nextSibling = node.nextSibling; + parentNode.insertBefore(node, end); + node = nextSibling; + } + }; + + // remove the nodes in the DOM representing this metamorph. + // + // this includes the starting and ending placeholders. + removeFunc = function() { + var start = realNode(document.getElementById(this.start)); + var end = document.getElementById(this.end); + + this.html(''); + start.parentNode.removeChild(start); + end.parentNode.removeChild(end); + }; + + appendToFunc = function(parentNode) { + var node = firstNodeFor(parentNode, this.outerHTML()); + var nextSibling; + + while (node) { + nextSibling = node.nextSibling; + parentNode.appendChild(node); + node = nextSibling; + } + }; + + afterFunc = function(html) { + // get the real starting node. see realNode for details. + var end = document.getElementById(this.end); + var insertBefore = end.nextSibling; + var parentNode = end.parentNode; + var nextSibling; + var node; + + // get the first node for the HTML string, even in cases like + // tables and lists where a simple innerHTML on a div would + // swallow some of the content. + node = firstNodeFor(parentNode, html); + + // copy the nodes for the HTML between the starting and ending + // placeholder. + while (node) { + nextSibling = node.nextSibling; + parentNode.insertBefore(node, insertBefore); + node = nextSibling; + } + }; + + prependFunc = function(html) { + var start = document.getElementById(this.start); + var parentNode = start.parentNode; + var nextSibling; + var node; + + node = firstNodeFor(parentNode, html); + var insertBefore = start.nextSibling; + + while (node) { + nextSibling = node.nextSibling; + parentNode.insertBefore(node, insertBefore); + node = nextSibling; + } + }; + } + + Metamorph.prototype.html = function(html) { + this.checkRemoved(); + if (html === undefined) { return this.innerHTML; } + + htmlFunc.call(this, html); + + this.innerHTML = html; + }; + + Metamorph.prototype.replaceWith = function(html) { + this.checkRemoved(); + htmlFunc.call(this, html, true); + }; + + Metamorph.prototype.remove = removeFunc; + Metamorph.prototype.outerHTML = outerHTMLFunc; + Metamorph.prototype.appendTo = appendToFunc; + Metamorph.prototype.after = afterFunc; + Metamorph.prototype.prepend = prependFunc; + Metamorph.prototype.startTag = startTagFunc; + Metamorph.prototype.endTag = endTagFunc; + + Metamorph.prototype.isRemoved = function() { + var before = document.getElementById(this.start); + var after = document.getElementById(this.end); + + return !before || !after; + }; + + Metamorph.prototype.checkRemoved = function() { + if (this.isRemoved()) { + throw new Error("Cannot perform operations on a Metamorph that is not in the DOM."); + } + }; + + return Metamorph; + }); + +})(); + +(function() { +/** +@module ember +@submodule ember-handlebars-compiler +*/ + +// Eliminate dependency on any Ember to simplify precompilation workflow +var objectCreate = Object.create || function(parent) { + function F() {} + F.prototype = parent; + return new F(); +}; + +var Handlebars = this.Handlebars || (Ember.imports && Ember.imports.Handlebars); +if (!Handlebars && typeof require === 'function') { + Handlebars = require('handlebars'); +} + +Ember.assert("Ember Handlebars requires Handlebars version 1.0 or 1.1. Include a SCRIPT tag in the HTML HEAD linking to the Handlebars file before you link to Ember.", Handlebars); +Ember.assert("Ember Handlebars requires Handlebars version 1.0 or 1.1, COMPILER_REVISION expected: 4, got: " + Handlebars.COMPILER_REVISION + " - Please note: Builds of master may have other COMPILER_REVISION values.", Handlebars.COMPILER_REVISION === 4); + +/** + Prepares the Handlebars templating library for use inside Ember's view + system. + + The `Ember.Handlebars` object is the standard Handlebars library, extended to + use Ember's `get()` method instead of direct property access, which allows + computed properties to be used inside templates. + + To create an `Ember.Handlebars` template, call `Ember.Handlebars.compile()`. + This will return a function that can be used by `Ember.View` for rendering. + + @class Handlebars + @namespace Ember +*/ +Ember.Handlebars = objectCreate(Handlebars); + +/** + Register a bound helper or custom view helper. + + ## Simple bound helper example + + ```javascript + Ember.Handlebars.helper('capitalize', function(value) { + return value.toUpperCase(); + }); + ``` + + The above bound helper can be used inside of templates as follows: + + ```handlebars + {{capitalize name}} + ``` + + In this case, when the `name` property of the template's context changes, + the rendered value of the helper will update to reflect this change. + + For more examples of bound helpers, see documentation for + `Ember.Handlebars.registerBoundHelper`. + + ## Custom view helper example + + Assuming a view subclass named `App.CalendarView` were defined, a helper + for rendering instances of this view could be registered as follows: + + ```javascript + Ember.Handlebars.helper('calendar', App.CalendarView): + ``` + + The above bound helper can be used inside of templates as follows: + + ```handlebars + {{calendar}} + ``` + + Which is functionally equivalent to: + + ```handlebars + {{view App.CalendarView}} + ``` + + Options in the helper will be passed to the view in exactly the same + manner as with the `view` helper. + + @method helper + @for Ember.Handlebars + @param {String} name + @param {Function|Ember.View} function or view class constructor + @param {String} dependentKeys* +*/ +Ember.Handlebars.helper = function(name, value) { + Ember.assert("You tried to register a component named '" + name + "', but component names must include a '-'", !Ember.Component.detect(value) || name.match(/-/)); + + if (Ember.View.detect(value)) { + Ember.Handlebars.registerHelper(name, Ember.Handlebars.makeViewHelper(value)); + } else { + Ember.Handlebars.registerBoundHelper.apply(null, arguments); + } +}; + +/** + @private + + Returns a helper function that renders the provided ViewClass. + + Used internally by Ember.Handlebars.helper and other methods + involving helper/component registration. + + @method helper + @for Ember.Handlebars + @param {Function} ViewClass view class constructor +*/ +Ember.Handlebars.makeViewHelper = function(ViewClass) { + return function(options) { + Ember.assert("You can only pass attributes (such as name=value) not bare values to a helper for a View", arguments.length < 2); + return Ember.Handlebars.helpers.view.call(this, ViewClass, options); + }; +}; + +/** +@class helpers +@namespace Ember.Handlebars +*/ +Ember.Handlebars.helpers = objectCreate(Handlebars.helpers); + +/** + Override the the opcode compiler and JavaScript compiler for Handlebars. + + @class Compiler + @namespace Ember.Handlebars + @private + @constructor +*/ +Ember.Handlebars.Compiler = function() {}; + +// Handlebars.Compiler doesn't exist in runtime-only +if (Handlebars.Compiler) { + Ember.Handlebars.Compiler.prototype = objectCreate(Handlebars.Compiler.prototype); +} + +Ember.Handlebars.Compiler.prototype.compiler = Ember.Handlebars.Compiler; + +/** + @class JavaScriptCompiler + @namespace Ember.Handlebars + @private + @constructor +*/ +Ember.Handlebars.JavaScriptCompiler = function() {}; + +// Handlebars.JavaScriptCompiler doesn't exist in runtime-only +if (Handlebars.JavaScriptCompiler) { + Ember.Handlebars.JavaScriptCompiler.prototype = objectCreate(Handlebars.JavaScriptCompiler.prototype); + Ember.Handlebars.JavaScriptCompiler.prototype.compiler = Ember.Handlebars.JavaScriptCompiler; +} + + +Ember.Handlebars.JavaScriptCompiler.prototype.namespace = "Ember.Handlebars"; + +Ember.Handlebars.JavaScriptCompiler.prototype.initializeBuffer = function() { + return "''"; +}; + +/** + @private + + Override the default buffer for Ember Handlebars. By default, Handlebars + creates an empty String at the beginning of each invocation and appends to + it. Ember's Handlebars overrides this to append to a single shared buffer. + + @method appendToBuffer + @param string {String} +*/ +Ember.Handlebars.JavaScriptCompiler.prototype.appendToBuffer = function(string) { + return "data.buffer.push("+string+");"; +}; + +// Hacks ahead: +// Handlebars presently has a bug where the `blockHelperMissing` hook +// doesn't get passed the name of the missing helper name, but rather +// gets passed the value of that missing helper evaluated on the current +// context, which is most likely `undefined` and totally useless. +// +// So we alter the compiled template function to pass the name of the helper +// instead, as expected. +// +// This can go away once the following is closed: +// https://github.com/wycats/handlebars.js/issues/617 + +var DOT_LOOKUP_REGEX = /helpers\.(.*?)\)/, + BRACKET_STRING_LOOKUP_REGEX = /helpers\['(.*?)'/, + INVOCATION_SPLITTING_REGEX = /(.*blockHelperMissing\.call\(.*)(stack[0-9]+)(,.*)/; + +Ember.Handlebars.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation = function(source) { + var helperInvocation = source[source.length - 1], + helperName = (DOT_LOOKUP_REGEX.exec(helperInvocation) || BRACKET_STRING_LOOKUP_REGEX.exec(helperInvocation))[1], + matches = INVOCATION_SPLITTING_REGEX.exec(helperInvocation); + + source[source.length - 1] = matches[1] + "'" + helperName + "'" + matches[3]; +} +var stringifyBlockHelperMissing = Ember.Handlebars.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation; + +var originalBlockValue = Ember.Handlebars.JavaScriptCompiler.prototype.blockValue; +Ember.Handlebars.JavaScriptCompiler.prototype.blockValue = function() { + originalBlockValue.apply(this, arguments); + stringifyBlockHelperMissing(this.source); +}; + +var originalAmbiguousBlockValue = Ember.Handlebars.JavaScriptCompiler.prototype.ambiguousBlockValue; +Ember.Handlebars.JavaScriptCompiler.prototype.ambiguousBlockValue = function() { + originalAmbiguousBlockValue.apply(this, arguments); + stringifyBlockHelperMissing(this.source); +}; + +var prefix = "ember" + (+new Date()), incr = 1; + +/** + @private + + Rewrite simple mustaches from `{{foo}}` to `{{bind "foo"}}`. This means that + all simple mustaches in Ember's Handlebars will also set up an observer to + keep the DOM up to date when the underlying property changes. + + @method mustache + @for Ember.Handlebars.Compiler + @param mustache +*/ +Ember.Handlebars.Compiler.prototype.mustache = function(mustache) { + if (mustache.isHelper && mustache.id.string === 'control') { + mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]); + mustache.hash.pairs.push(["controlID", new Handlebars.AST.StringNode(prefix + incr++)]); + } else if (mustache.params.length || mustache.hash) { + // no changes required + } else { + var id = new Handlebars.AST.IdNode([{ part: '_triageMustache' }]); + + // Update the mustache node to include a hash value indicating whether the original node + // was escaped. This will allow us to properly escape values when the underlying value + // changes and we need to re-render the value. + if (!mustache.escaped) { + mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]); + mustache.hash.pairs.push(["unescaped", new Handlebars.AST.StringNode("true")]); + } + mustache = new Handlebars.AST.MustacheNode([id].concat([mustache.id]), mustache.hash, !mustache.escaped); + } + + return Handlebars.Compiler.prototype.mustache.call(this, mustache); +}; + +/** + Used for precompilation of Ember Handlebars templates. This will not be used + during normal app execution. + + @method precompile + @for Ember.Handlebars + @static + @param {String} string The template to precompile +*/ +Ember.Handlebars.precompile = function(string) { + var ast = Handlebars.parse(string); + + var options = { + knownHelpers: { + action: true, + unbound: true, + bindAttr: true, + template: true, + view: true, + _triageMustache: true + }, + data: true, + stringParams: true + }; + + var environment = new Ember.Handlebars.Compiler().compile(ast, options); + return new Ember.Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true); +}; + +// We don't support this for Handlebars runtime-only +if (Handlebars.compile) { + /** + The entry point for Ember Handlebars. This replaces the default + `Handlebars.compile` and turns on template-local data and String + parameters. + + @method compile + @for Ember.Handlebars + @static + @param {String} string The template to compile + @return {Function} + */ + Ember.Handlebars.compile = function(string) { + var ast = Handlebars.parse(string); + var options = { data: true, stringParams: true }; + var environment = new Ember.Handlebars.Compiler().compile(ast, options); + var templateSpec = new Ember.Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true); + + var template = Ember.Handlebars.template(templateSpec); + template.isMethod = false; //Make sure we don't wrap templates with ._super + + return template; + }; +} + + +})(); + +(function() { +var slice = Array.prototype.slice, + originalTemplate = Ember.Handlebars.template; + +/** + @private + + If a path starts with a reserved keyword, returns the root + that should be used. + + @method normalizePath + @for Ember + @param root {Object} + @param path {String} + @param data {Hash} +*/ +var normalizePath = Ember.Handlebars.normalizePath = function(root, path, data) { + var keywords = (data && data.keywords) || {}, + keyword, isKeyword; + + // Get the first segment of the path. For example, if the + // path is "foo.bar.baz", returns "foo". + keyword = path.split('.', 1)[0]; + + // Test to see if the first path is a keyword that has been + // passed along in the view's data hash. If so, we will treat + // that object as the new root. + if (keywords.hasOwnProperty(keyword)) { + // Look up the value in the template's data hash. + root = keywords[keyword]; + isKeyword = true; + + // Handle cases where the entire path is the reserved + // word. In that case, return the object itself. + if (path === keyword) { + path = ''; + } else { + // Strip the keyword from the path and look up + // the remainder from the newly found root. + path = path.substr(keyword.length+1); + } + } + + return { root: root, path: path, isKeyword: isKeyword }; +}; + + +/** + Lookup both on root and on window. If the path starts with + a keyword, the corresponding object will be looked up in the + template's data hash and used to resolve the path. + + @method get + @for Ember.Handlebars + @param {Object} root The object to look up the property on + @param {String} path The path to be lookedup + @param {Object} options The template's option hash +*/ +var handlebarsGet = Ember.Handlebars.get = function(root, path, options) { + var data = options && options.data, + normalizedPath = normalizePath(root, path, data), + value; + + // In cases where the path begins with a keyword, change the + // root to the value represented by that keyword, and ensure + // the path is relative to it. + root = normalizedPath.root; + path = normalizedPath.path; + + value = Ember.get(root, path); + + // If the path starts with a capital letter, look it up on Ember.lookup, + // which defaults to the `window` object in browsers. + if (value === undefined && root !== Ember.lookup && Ember.isGlobalPath(path)) { + value = Ember.get(Ember.lookup, path); + } + return value; +}; + +Ember.Handlebars.resolveParams = function(context, params, options) { + var resolvedParams = [], types = options.types, param, type; + + for (var i=0, l=params.length; isomeString') + ``` + + @method htmlSafe + @for Ember.String + @static + @return {Handlebars.SafeString} a string that will not be html escaped by Handlebars +*/ +Ember.String.htmlSafe = function(str) { + return new Handlebars.SafeString(str); +}; + +var htmlSafe = Ember.String.htmlSafe; + +if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) { + + /** + Mark a string as being safe for unescaped output with Handlebars. + + ```javascript + '
    someString
    '.htmlSafe() + ``` + + See [Ember.String.htmlSafe](/api/classes/Ember.String.html#method_htmlSafe). + + @method htmlSafe + @for String + @return {Handlebars.SafeString} a string that will not be html escaped by Handlebars + */ + String.prototype.htmlSafe = function() { + return htmlSafe(this); + }; +} + +})(); + + + +(function() { +Ember.Handlebars.resolvePaths = function(options) { + var ret = [], + contexts = options.contexts, + roots = options.roots, + data = options.data; + + for (var i=0, l=contexts.length; i + ``` + + The above handlebars template will fill the ``'s `src` attribute will + the value of the property referenced with `"imageUrl"` and its `alt` + attribute with the value of the property referenced with `"imageTitle"`. + + If the rendering context of this template is the following object: + + ```javascript + { + imageUrl: 'http://lolcats.info/haz-a-funny', + imageTitle: 'A humorous image of a cat' + } + ``` + + The resulting HTML output will be: + + ```html + A humorous image of a cat + ``` + + `bind-attr` cannot redeclare existing DOM element attributes. The use of `src` + in the following `bind-attr` example will be ignored and the hard coded value + of `src="/failwhale.gif"` will take precedence: + + ```handlebars + imageTitle + ``` + + ### `bind-attr` and the `class` attribute + + `bind-attr` supports a special syntax for handling a number of cases unique + to the `class` DOM element attribute. The `class` attribute combines + multiple discrete values into a single attribute as a space-delimited + list of strings. Each string can be: + + * a string return value of an object's property. + * a boolean return value of an object's property + * a hard-coded value + + A string return value works identically to other uses of `bind-attr`. The + return value of the property will become the value of the attribute. For + example, the following view and template: + + ```javascript + AView = Ember.View.extend({ + someProperty: function() { + return "aValue"; + }.property() + }) + ``` + + ```handlebars + + ``` + + A boolean return value will insert a specified class name if the property + returns `true` and remove the class name if the property returns `false`. + + A class name is provided via the syntax + `somePropertyName:class-name-if-true`. + + ```javascript + AView = Ember.View.extend({ + someBool: true + }) + ``` + + ```handlebars + + ``` + + Result in the following rendered output: + + ```html + + ``` + + An additional section of the binding can be provided if you want to + replace the existing class instead of removing it when the boolean + value changes: + + ```handlebars + + ``` + + A hard-coded value can be used by prepending `:` to the desired + class name: `:class-name-to-always-apply`. + + ```handlebars + + ``` + + Results in the following rendered output: + + ```html + + ``` + + All three strategies - string return value, boolean return value, and + hard-coded value – can be combined in a single declaration: + + ```handlebars + + ``` + + @method bind-attr + @for Ember.Handlebars.helpers + @param {Hash} options + @return {String} HTML string +*/ +EmberHandlebars.registerHelper('bind-attr', function(options) { + + var attrs = options.hash; + + Ember.assert("You must specify at least one hash argument to bind-attr", !!Ember.keys(attrs).length); + + var view = options.data.view; + var ret = []; + var ctx = this; + + // Generate a unique id for this element. This will be added as a + // data attribute to the element so it can be looked up when + // the bound property changes. + var dataId = ++Ember.uuid; + + // Handle classes differently, as we can bind multiple classes + var classBindings = attrs['class']; + if (classBindings != null) { + var classResults = EmberHandlebars.bindClasses(this, classBindings, view, dataId, options); + + ret.push('class="' + Handlebars.Utils.escapeExpression(classResults.join(' ')) + '"'); + delete attrs['class']; + } + + var attrKeys = Ember.keys(attrs); + + // For each attribute passed, create an observer and emit the + // current value of the property as an attribute. + forEach.call(attrKeys, function(attr) { + var path = attrs[attr], + normalized; + + Ember.assert(fmt("You must provide an expression as the value of bound attribute. You specified: %@=%@", [attr, path]), typeof path === 'string'); + + normalized = normalizePath(ctx, path, options.data); + + var value = (path === 'this') ? normalized.root : handlebarsGet(ctx, path, options), + type = Ember.typeOf(value); + + Ember.assert(fmt("Attributes must be numbers, strings or booleans, not %@", [value]), value === null || value === undefined || type === 'number' || type === 'string' || type === 'boolean'); + + var observer, invoker; + + observer = function observer() { + var result = handlebarsGet(ctx, path, options); + + Ember.assert(fmt("Attributes must be numbers, strings or booleans, not %@", [result]), result === null || result === undefined || typeof result === 'number' || typeof result === 'string' || typeof result === 'boolean'); + + var elem = view.$("[data-bindattr-" + dataId + "='" + dataId + "']"); + + // If we aren't able to find the element, it means the element + // to which we were bound has been removed from the view. + // In that case, we can assume the template has been re-rendered + // and we need to clean up the observer. + if (!elem || elem.length === 0) { + Ember.removeObserver(normalized.root, normalized.path, invoker); + return; + } + + Ember.View.applyAttributeBindings(elem, attr, result); + }; + + // Add an observer to the view for when the property changes. + // When the observer fires, find the element using the + // unique data id and update the attribute to the new value. + // Note: don't add observer when path is 'this' or path + // is whole keyword e.g. {{#each x in list}} ... {{bind-attr attr="x"}} + if (path !== 'this' && !(normalized.isKeyword && normalized.path === '' )) { + view.registerObserver(normalized.root, normalized.path, observer); + } + + // if this changes, also change the logic in ember-views/lib/views/view.js + if ((type === 'string' || (type === 'number' && !isNaN(value)))) { + ret.push(attr + '="' + Handlebars.Utils.escapeExpression(value) + '"'); + } else if (value && type === 'boolean') { + // The developer controls the attr name, so it should always be safe + ret.push(attr + '="' + attr + '"'); + } + }, this); + + // Add the unique identifier + // NOTE: We use all lower-case since Firefox has problems with mixed case in SVG + ret.push('data-bindattr-' + dataId + '="' + dataId + '"'); + return new EmberHandlebars.SafeString(ret.join(' ')); +}); + +/** + See `bind-attr` + + @method bindAttr + @for Ember.Handlebars.helpers + @deprecated + @param {Function} context + @param {Hash} options + @return {String} HTML string +*/ +EmberHandlebars.registerHelper('bindAttr', EmberHandlebars.helpers['bind-attr']); + +/** + @private + + Helper that, given a space-separated string of property paths and a context, + returns an array of class names. Calling this method also has the side + effect of setting up observers at those property paths, such that if they + change, the correct class name will be reapplied to the DOM element. + + For example, if you pass the string "fooBar", it will first look up the + "fooBar" value of the context. If that value is true, it will add the + "foo-bar" class to the current element (i.e., the dasherized form of + "fooBar"). If the value is a string, it will add that string as the class. + Otherwise, it will not add any new class name. + + @method bindClasses + @for Ember.Handlebars + @param {Ember.Object} context The context from which to lookup properties + @param {String} classBindings A string, space-separated, of class bindings + to use + @param {Ember.View} view The view in which observers should look for the + element to update + @param {Srting} bindAttrId Optional bindAttr id used to lookup elements + @return {Array} An array of class names to add +*/ +EmberHandlebars.bindClasses = function(context, classBindings, view, bindAttrId, options) { + var ret = [], newClass, value, elem; + + // Helper method to retrieve the property from the context and + // determine which class string to return, based on whether it is + // a Boolean or not. + var classStringForPath = function(root, parsedPath, options) { + var val, + path = parsedPath.path; + + if (path === 'this') { + val = root; + } else if (path === '') { + val = true; + } else { + val = handlebarsGet(root, path, options); + } + + return Ember.View._classStringForValue(path, val, parsedPath.className, parsedPath.falsyClassName); + }; + + // For each property passed, loop through and setup + // an observer. + forEach.call(classBindings.split(' '), function(binding) { + + // Variable in which the old class value is saved. The observer function + // closes over this variable, so it knows which string to remove when + // the property changes. + var oldClass; + + var observer, invoker; + + var parsedPath = Ember.View._parsePropertyPath(binding), + path = parsedPath.path, + pathRoot = context, + normalized; + + if (path !== '' && path !== 'this') { + normalized = normalizePath(context, path, options.data); + + pathRoot = normalized.root; + path = normalized.path; + } + + // Set up an observer on the context. If the property changes, toggle the + // class name. + observer = function() { + // Get the current value of the property + newClass = classStringForPath(context, parsedPath, options); + elem = bindAttrId ? view.$("[data-bindattr-" + bindAttrId + "='" + bindAttrId + "']") : view.$(); + + // If we can't find the element anymore, a parent template has been + // re-rendered and we've been nuked. Remove the observer. + if (!elem || elem.length === 0) { + Ember.removeObserver(pathRoot, path, invoker); + } else { + // If we had previously added a class to the element, remove it. + if (oldClass) { + elem.removeClass(oldClass); + } + + // If necessary, add a new class. Make sure we keep track of it so + // it can be removed in the future. + if (newClass) { + elem.addClass(newClass); + oldClass = newClass; + } else { + oldClass = null; + } + } + }; + + if (path !== '' && path !== 'this') { + view.registerObserver(pathRoot, path, observer); + } + + // We've already setup the observer; now we just need to figure out the + // correct behavior right now on the first pass through. + value = classStringForPath(context, parsedPath, options); + + if (value) { + ret.push(value); + + // Make sure we save the current value so that it can be removed if the + // observer fires. + oldClass = value; + } + }); + + return ret; +}; + + +})(); + + + +(function() { +/*globals Handlebars */ + +// TODO: Don't require the entire module +/** +@module ember +@submodule ember-handlebars +*/ + +var get = Ember.get, set = Ember.set; +var EmberHandlebars = Ember.Handlebars; +var LOWERCASE_A_Z = /^[a-z]/; +var VIEW_PREFIX = /^view\./; + +function makeBindings(thisContext, options) { + var hash = options.hash, + hashType = options.hashTypes; + + for (var prop in hash) { + if (hashType[prop] === 'ID') { + + var value = hash[prop]; + + if (Ember.IS_BINDING.test(prop)) { + Ember.warn("You're attempting to render a view by passing " + prop + "=" + value + " to a view helper, but this syntax is ambiguous. You should either surround " + value + " in quotes or remove `Binding` from " + prop + "."); + } else { + hash[prop + 'Binding'] = value; + hashType[prop + 'Binding'] = 'STRING'; + delete hash[prop]; + delete hashType[prop]; + } + } + } + + if (hash.hasOwnProperty('idBinding')) { + // id can't be bound, so just perform one-time lookup. + hash.id = EmberHandlebars.get(thisContext, hash.idBinding, options); + hashType.id = 'STRING'; + delete hash.idBinding; + delete hashType.idBinding; + } +} + +EmberHandlebars.ViewHelper = Ember.Object.create({ + + propertiesFromHTMLOptions: function(options) { + var hash = options.hash, data = options.data; + var extensions = {}, + classes = hash['class'], + dup = false; + + if (hash.id) { + extensions.elementId = hash.id; + dup = true; + } + + if (hash.tag) { + extensions.tagName = hash.tag; + dup = true; + } + + if (classes) { + classes = classes.split(' '); + extensions.classNames = classes; + dup = true; + } + + if (hash.classBinding) { + extensions.classNameBindings = hash.classBinding.split(' '); + dup = true; + } + + if (hash.classNameBindings) { + if (extensions.classNameBindings === undefined) extensions.classNameBindings = []; + extensions.classNameBindings = extensions.classNameBindings.concat(hash.classNameBindings.split(' ')); + dup = true; + } + + if (hash.attributeBindings) { + Ember.assert("Setting 'attributeBindings' via Handlebars is not allowed. Please subclass Ember.View and set it there instead."); + extensions.attributeBindings = null; + dup = true; + } + + if (dup) { + hash = Ember.$.extend({}, hash); + delete hash.id; + delete hash.tag; + delete hash['class']; + delete hash.classBinding; + } + + // Set the proper context for all bindings passed to the helper. This applies to regular attribute bindings + // as well as class name bindings. If the bindings are local, make them relative to the current context + // instead of the view. + var path; + + // Evaluate the context of regular attribute bindings: + for (var prop in hash) { + if (!hash.hasOwnProperty(prop)) { continue; } + + // Test if the property ends in "Binding" + if (Ember.IS_BINDING.test(prop) && typeof hash[prop] === 'string') { + path = this.contextualizeBindingPath(hash[prop], data); + if (path) { hash[prop] = path; } + } + } + + // Evaluate the context of class name bindings: + if (extensions.classNameBindings) { + for (var b in extensions.classNameBindings) { + var full = extensions.classNameBindings[b]; + if (typeof full === 'string') { + // Contextualize the path of classNameBinding so this: + // + // classNameBinding="isGreen:green" + // + // is converted to this: + // + // classNameBinding="_parentView.context.isGreen:green" + var parsedPath = Ember.View._parsePropertyPath(full); + path = this.contextualizeBindingPath(parsedPath.path, data); + if (path) { extensions.classNameBindings[b] = path + parsedPath.classNames; } + } + } + } + + return Ember.$.extend(hash, extensions); + }, + + // Transform bindings from the current context to a context that can be evaluated within the view. + // Returns null if the path shouldn't be changed. + // + // TODO: consider the addition of a prefix that would allow this method to return `path`. + contextualizeBindingPath: function(path, data) { + var normalized = Ember.Handlebars.normalizePath(null, path, data); + if (normalized.isKeyword) { + return 'templateData.keywords.' + path; + } else if (Ember.isGlobalPath(path)) { + return null; + } else if (path === 'this') { + return '_parentView.context'; + } else { + return '_parentView.context.' + path; + } + }, + + helper: function(thisContext, path, options) { + var data = options.data, + fn = options.fn, + newView; + + makeBindings(thisContext, options); + + if ('string' === typeof path) { + + // TODO: this is a lame conditional, this should likely change + // but something along these lines will likely need to be added + // as deprecation warnings + // + if (options.types[0] === 'STRING' && LOWERCASE_A_Z.test(path) && !VIEW_PREFIX.test(path)) { + Ember.assert("View requires a container", !!data.view.container); + newView = data.view.container.lookupFactory('view:' + path); + } else { + newView = EmberHandlebars.get(thisContext, path, options); + } + + Ember.assert("Unable to find view at path '" + path + "'", !!newView); + } else { + newView = path; + } + + Ember.assert(Ember.String.fmt('You must pass a view to the #view helper, not %@ (%@)', [path, newView]), Ember.View.detect(newView) || Ember.View.detectInstance(newView)); + + var viewOptions = this.propertiesFromHTMLOptions(options, thisContext); + var currentView = data.view; + viewOptions.templateData = data; + var newViewProto = newView.proto ? newView.proto() : newView; + + if (fn) { + Ember.assert("You cannot provide a template block if you also specified a templateName", !get(viewOptions, 'templateName') && !get(newViewProto, 'templateName')); + viewOptions.template = fn; + } + + // We only want to override the `_context` computed property if there is + // no specified controller. See View#_context for more information. + if (!newViewProto.controller && !newViewProto.controllerBinding && !viewOptions.controller && !viewOptions.controllerBinding) { + viewOptions._context = thisContext; + } + + currentView.appendChild(newView, viewOptions); + } +}); + +/** + `{{view}}` inserts a new instance of `Ember.View` into a template passing its + options to the `Ember.View`'s `create` method and using the supplied block as + the view's own template. + + An empty `` and the following template: + + ```handlebars + A span: + {{#view tagName="span"}} + hello. + {{/view}} + ``` + + Will result in HTML structure: + + ```html + + + +
    + A span: + + Hello. + +
    + + ``` + + ### `parentView` setting + + The `parentView` property of the new `Ember.View` instance created through + `{{view}}` will be set to the `Ember.View` instance of the template where + `{{view}}` was called. + + ```javascript + aView = Ember.View.create({ + template: Ember.Handlebars.compile("{{#view}} my parent: {{parentView.elementId}} {{/view}}") + }); + + aView.appendTo('body'); + ``` + + Will result in HTML structure: + + ```html +
    +
    + my parent: ember1 +
    +
    + ``` + + ### Setting CSS id and class attributes + + The HTML `id` attribute can be set on the `{{view}}`'s resulting element with + the `id` option. This option will _not_ be passed to `Ember.View.create`. + + ```handlebars + {{#view tagName="span" id="a-custom-id"}} + hello. + {{/view}} + ``` + + Results in the following HTML structure: + + ```html +
    + + hello. + +
    + ``` + + The HTML `class` attribute can be set on the `{{view}}`'s resulting element + with the `class` or `classNameBindings` options. The `class` option will + directly set the CSS `class` attribute and will not be passed to + `Ember.View.create`. `classNameBindings` will be passed to `create` and use + `Ember.View`'s class name binding functionality: + + ```handlebars + {{#view tagName="span" class="a-custom-class"}} + hello. + {{/view}} + ``` + + Results in the following HTML structure: + + ```html +
    + + hello. + +
    + ``` + + ### Supplying a different view class + + `{{view}}` can take an optional first argument before its supplied options to + specify a path to a custom view class. + + ```handlebars + {{#view "MyApp.CustomView"}} + hello. + {{/view}} + ``` + + The first argument can also be a relative path accessible from the current + context. + + ```javascript + MyApp = Ember.Application.create({}); + MyApp.OuterView = Ember.View.extend({ + innerViewClass: Ember.View.extend({ + classNames: ['a-custom-view-class-as-property'] + }), + template: Ember.Handlebars.compile('{{#view "view.innerViewClass"}} hi {{/view}}') + }); + + MyApp.OuterView.create().appendTo('body'); + ``` + + Will result in the following HTML: + + ```html +
    +
    + hi +
    +
    + ``` + + ### Blockless use + + If you supply a custom `Ember.View` subclass that specifies its own template + or provide a `templateName` option to `{{view}}` it can be used without + supplying a block. Attempts to use both a `templateName` option and supply a + block will throw an error. + + ```handlebars + {{view "MyApp.ViewWithATemplateDefined"}} + ``` + + ### `viewName` property + + You can supply a `viewName` option to `{{view}}`. The `Ember.View` instance + will be referenced as a property of its parent view by this name. + + ```javascript + aView = Ember.View.create({ + template: Ember.Handlebars.compile('{{#view viewName="aChildByName"}} hi {{/view}}') + }); + + aView.appendTo('body'); + aView.get('aChildByName') // the instance of Ember.View created by {{view}} helper + ``` + + @method view + @for Ember.Handlebars.helpers + @param {String} path + @param {Hash} options + @return {String} HTML string +*/ +EmberHandlebars.registerHelper('view', function(path, options) { + Ember.assert("The view helper only takes a single argument", arguments.length <= 2); + + // If no path is provided, treat path param as options. + if (path && path.data && path.data.isRenderData) { + options = path; + path = "Ember.View"; + } + + return EmberHandlebars.ViewHelper.helper(this, path, options); +}); + + +})(); + + + +(function() { +/*globals Handlebars */ + +// TODO: Don't require all of this module +/** +@module ember +@submodule ember-handlebars +*/ + +var get = Ember.get, handlebarsGet = Ember.Handlebars.get, fmt = Ember.String.fmt; + +/** + `{{collection}}` is a `Ember.Handlebars` helper for adding instances of + `Ember.CollectionView` to a template. See [Ember.CollectionView](/api/classes/Ember.CollectionView.html) + for additional information on how a `CollectionView` functions. + + `{{collection}}`'s primary use is as a block helper with a `contentBinding` + option pointing towards an `Ember.Array`-compatible object. An `Ember.View` + instance will be created for each item in its `content` property. Each view + will have its own `content` property set to the appropriate item in the + collection. + + The provided block will be applied as the template for each item's view. + + Given an empty `` the following template: + + ```handlebars + {{#collection contentBinding="App.items"}} + Hi {{view.content.name}} + {{/collection}} + ``` + + And the following application code + + ```javascript + App = Ember.Application.create() + App.items = [ + Ember.Object.create({name: 'Dave'}), + Ember.Object.create({name: 'Mary'}), + Ember.Object.create({name: 'Sara'}) + ] + ``` + + Will result in the HTML structure below + + ```html +
    +
    Hi Dave
    +
    Hi Mary
    +
    Hi Sara
    +
    + ``` + + ### Blockless Use + + If you provide an `itemViewClass` option that has its own `template` you can + omit the block. + + The following template: + + ```handlebars + {{collection contentBinding="App.items" itemViewClass="App.AnItemView"}} + ``` + + And application code + + ```javascript + App = Ember.Application.create(); + App.items = [ + Ember.Object.create({name: 'Dave'}), + Ember.Object.create({name: 'Mary'}), + Ember.Object.create({name: 'Sara'}) + ]; + + App.AnItemView = Ember.View.extend({ + template: Ember.Handlebars.compile("Greetings {{view.content.name}}") + }); + ``` + + Will result in the HTML structure below + + ```html +
    +
    Greetings Dave
    +
    Greetings Mary
    +
    Greetings Sara
    +
    + ``` + + ### Specifying a CollectionView subclass + + By default the `{{collection}}` helper will create an instance of + `Ember.CollectionView`. You can supply a `Ember.CollectionView` subclass to + the helper by passing it as the first argument: + + ```handlebars + {{#collection App.MyCustomCollectionClass contentBinding="App.items"}} + Hi {{view.content.name}} + {{/collection}} + ``` + + ### Forwarded `item.*`-named Options + + As with the `{{view}}`, helper options passed to the `{{collection}}` will be + set on the resulting `Ember.CollectionView` as properties. Additionally, + options prefixed with `item` will be applied to the views rendered for each + item (note the camelcasing): + + ```handlebars + {{#collection contentBinding="App.items" + itemTagName="p" + itemClassNames="greeting"}} + Howdy {{view.content.name}} + {{/collection}} + ``` + + Will result in the following HTML structure: + + ```html +
    +

    Howdy Dave

    +

    Howdy Mary

    +

    Howdy Sara

    +
    + ``` + + @method collection + @for Ember.Handlebars.helpers + @param {String} path + @param {Hash} options + @return {String} HTML string + @deprecated Use `{{each}}` helper instead. +*/ +Ember.Handlebars.registerHelper('collection', function(path, options) { + Ember.deprecate("Using the {{collection}} helper without specifying a class has been deprecated as the {{each}} helper now supports the same functionality.", path !== 'collection'); + + // If no path is provided, treat path param as options. + if (path && path.data && path.data.isRenderData) { + options = path; + path = undefined; + Ember.assert("You cannot pass more than one argument to the collection helper", arguments.length === 1); + } else { + Ember.assert("You cannot pass more than one argument to the collection helper", arguments.length === 2); + } + + var fn = options.fn; + var data = options.data; + var inverse = options.inverse; + var view = options.data.view; + + // If passed a path string, convert that into an object. + // Otherwise, just default to the standard class. + var collectionClass; + collectionClass = path ? handlebarsGet(this, path, options) : Ember.CollectionView; + Ember.assert(fmt("%@ #collection: Could not find collection class %@", [data.view, path]), !!collectionClass); + + var hash = options.hash, itemHash = {}, match; + + // Extract item view class if provided else default to the standard class + var collectionPrototype = collectionClass.proto(), + itemViewClass; + + if (hash.itemView) { + var controller = data.keywords.controller; + Ember.assert('You specified an itemView, but the current context has no container to look the itemView up in. This probably means that you created a view manually, instead of through the container. Instead, use container.lookup("view:viewName"), which will properly instantiate your view.', controller && controller.container); + var container = controller.container; + itemViewClass = container.resolve('view:' + hash.itemView); + Ember.assert('You specified the itemView ' + hash.itemView + ", but it was not found at " + container.describe("view:" + hash.itemView) + " (and it was not registered in the container)", !!itemViewClass); + } else if (hash.itemViewClass) { + itemViewClass = handlebarsGet(collectionPrototype, hash.itemViewClass, options); + } else { + itemViewClass = collectionPrototype.itemViewClass; + } + + Ember.assert(fmt("%@ #collection: Could not find itemViewClass %@", [data.view, itemViewClass]), !!itemViewClass); + + delete hash.itemViewClass; + delete hash.itemView; + + // Go through options passed to the {{collection}} helper and extract options + // that configure item views instead of the collection itself. + for (var prop in hash) { + if (hash.hasOwnProperty(prop)) { + match = prop.match(/^item(.)(.*)$/); + + if (match && prop !== 'itemController') { + // Convert itemShouldFoo -> shouldFoo + itemHash[match[1].toLowerCase() + match[2]] = hash[prop]; + // Delete from hash as this will end up getting passed to the + // {{view}} helper method. + delete hash[prop]; + } + } + } + + if (fn) { + itemHash.template = fn; + delete options.fn; + } + + var emptyViewClass; + if (inverse && inverse !== Handlebars.VM.noop) { + emptyViewClass = get(collectionPrototype, 'emptyViewClass'); + emptyViewClass = emptyViewClass.extend({ + template: inverse, + tagName: itemHash.tagName + }); + } else if (hash.emptyViewClass) { + emptyViewClass = handlebarsGet(this, hash.emptyViewClass, options); + } + if (emptyViewClass) { hash.emptyView = emptyViewClass; } + + if (!hash.keyword) { + itemHash._context = Ember.computed.alias('content'); + } + + var viewOptions = Ember.Handlebars.ViewHelper.propertiesFromHTMLOptions({ data: data, hash: itemHash }, this); + hash.itemViewClass = itemViewClass.extend(viewOptions); + + return Ember.Handlebars.helpers.view.call(this, collectionClass, options); +}); + + +})(); + + + +(function() { +/*globals Handlebars */ +/** +@module ember +@submodule ember-handlebars +*/ + +var handlebarsGet = Ember.Handlebars.get; + +/** + `unbound` allows you to output a property without binding. *Important:* The + output will not be updated if the property changes. Use with caution. + + ```handlebars +
    {{unbound somePropertyThatDoesntChange}}
    + ``` + + `unbound` can also be used in conjunction with a bound helper to + render it in its unbound form: + + ```handlebars +
    {{unbound helperName somePropertyThatDoesntChange}}
    + ``` + + @method unbound + @for Ember.Handlebars.helpers + @param {String} property + @return {String} HTML string +*/ +Ember.Handlebars.registerHelper('unbound', function(property, fn) { + var options = arguments[arguments.length - 1], helper, context, out; + + if (arguments.length > 2) { + // Unbound helper call. + options.data.isUnbound = true; + helper = Ember.Handlebars.helpers[arguments[0]] || Ember.Handlebars.helperMissing; + out = helper.apply(this, Array.prototype.slice.call(arguments, 1)); + delete options.data.isUnbound; + return out; + } + + context = (fn.contexts && fn.contexts.length) ? fn.contexts[0] : this; + return handlebarsGet(context, property, fn); +}); + +})(); + + + +(function() { +/*jshint debug:true*/ +/** +@module ember +@submodule ember-handlebars +*/ + +var handlebarsGet = Ember.Handlebars.get, normalizePath = Ember.Handlebars.normalizePath; + +/** + `log` allows you to output the value of a variable in the current rendering + context. + + ```handlebars + {{log myVariable}} + ``` + + @method log + @for Ember.Handlebars.helpers + @param {String} property +*/ +Ember.Handlebars.registerHelper('log', function(property, options) { + var context = (options.contexts && options.contexts.length) ? options.contexts[0] : this, + normalized = normalizePath(context, property, options.data), + pathRoot = normalized.root, + path = normalized.path, + value = (path === 'this') ? pathRoot : handlebarsGet(pathRoot, path, options); + Ember.Logger.log(value); +}); + +/** + Execute the `debugger` statement in the current context. + + ```handlebars + {{debugger}} + ``` + + @method debugger + @for Ember.Handlebars.helpers + @param {String} property +*/ +Ember.Handlebars.registerHelper('debugger', function(options) { + debugger; +}); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-handlebars +*/ + +var get = Ember.get, set = Ember.set; + +Ember.Handlebars.EachView = Ember.CollectionView.extend(Ember._Metamorph, { + init: function() { + var itemController = get(this, 'itemController'); + var binding; + + if (itemController) { + var controller = get(this, 'controller.container').lookupFactory('controller:array').create({ + parentController: get(this, 'controller'), + itemController: itemController, + target: get(this, 'controller'), + _eachView: this + }); + + this.disableContentObservers(function() { + set(this, 'content', controller); + binding = new Ember.Binding('content', '_eachView.dataSource').oneWay(); + binding.connect(controller); + }); + + set(this, '_arrayController', controller); + } else { + this.disableContentObservers(function() { + binding = new Ember.Binding('content', 'dataSource').oneWay(); + binding.connect(this); + }); + } + + return this._super(); + }, + + _assertArrayLike: function(content) { + Ember.assert("The value that #each loops over must be an Array. You passed " + content.constructor + ", but it should have been an ArrayController", !Ember.ControllerMixin.detect(content) || (content && content.isGenerated) || content instanceof Ember.ArrayController); + Ember.assert("The value that #each loops over must be an Array. You passed " + ((Ember.ControllerMixin.detect(content) && content.get('model') !== undefined) ? ("" + content.get('model') + " (wrapped in " + content + ")") : ("" + content)), Ember.Array.detect(content)); + }, + + disableContentObservers: function(callback) { + Ember.removeBeforeObserver(this, 'content', null, '_contentWillChange'); + Ember.removeObserver(this, 'content', null, '_contentDidChange'); + + callback.call(this); + + Ember.addBeforeObserver(this, 'content', null, '_contentWillChange'); + Ember.addObserver(this, 'content', null, '_contentDidChange'); + }, + + itemViewClass: Ember._MetamorphView, + emptyViewClass: Ember._MetamorphView, + + createChildView: function(view, attrs) { + view = this._super(view, attrs); + + // At the moment, if a container view subclass wants + // to insert keywords, it is responsible for cloning + // the keywords hash. This will be fixed momentarily. + var keyword = get(this, 'keyword'); + var content = get(view, 'content'); + + if (keyword) { + var data = get(view, 'templateData'); + + data = Ember.copy(data); + data.keywords = view.cloneKeywords(); + set(view, 'templateData', data); + + // In this case, we do not bind, because the `content` of + // a #each item cannot change. + data.keywords[keyword] = content; + } + + // If {{#each}} is looping over an array of controllers, + // point each child view at their respective controller. + if (content && get(content, 'isController')) { + set(view, 'controller', content); + } + + return view; + }, + + destroy: function() { + if (!this._super()) { return; } + + var arrayController = get(this, '_arrayController'); + + if (arrayController) { + arrayController.destroy(); + } + + return this; + } +}); + +var GroupedEach = Ember.Handlebars.GroupedEach = function(context, path, options) { + var self = this, + normalized = Ember.Handlebars.normalizePath(context, path, options.data); + + this.context = context; + this.path = path; + this.options = options; + this.template = options.fn; + this.containingView = options.data.view; + this.normalizedRoot = normalized.root; + this.normalizedPath = normalized.path; + this.content = this.lookupContent(); + + this.addContentObservers(); + this.addArrayObservers(); + + this.containingView.on('willClearRender', function() { + self.destroy(); + }); +}; + +GroupedEach.prototype = { + contentWillChange: function() { + this.removeArrayObservers(); + }, + + contentDidChange: function() { + this.content = this.lookupContent(); + this.addArrayObservers(); + this.rerenderContainingView(); + }, + + contentArrayWillChange: Ember.K, + + contentArrayDidChange: function() { + this.rerenderContainingView(); + }, + + lookupContent: function() { + return Ember.Handlebars.get(this.normalizedRoot, this.normalizedPath, this.options); + }, + + addArrayObservers: function() { + if (!this.content) { return; } + + this.content.addArrayObserver(this, { + willChange: 'contentArrayWillChange', + didChange: 'contentArrayDidChange' + }); + }, + + removeArrayObservers: function() { + if (!this.content) { return; } + + this.content.removeArrayObserver(this, { + willChange: 'contentArrayWillChange', + didChange: 'contentArrayDidChange' + }); + }, + + addContentObservers: function() { + Ember.addBeforeObserver(this.normalizedRoot, this.normalizedPath, this, this.contentWillChange); + Ember.addObserver(this.normalizedRoot, this.normalizedPath, this, this.contentDidChange); + }, + + removeContentObservers: function() { + Ember.removeBeforeObserver(this.normalizedRoot, this.normalizedPath, this.contentWillChange); + Ember.removeObserver(this.normalizedRoot, this.normalizedPath, this.contentDidChange); + }, + + render: function() { + if (!this.content) { return; } + + var content = this.content, + contentLength = get(content, 'length'), + data = this.options.data, + template = this.template; + + data.insideEach = true; + for (var i = 0; i < contentLength; i++) { + template(content.objectAt(i), { data: data }); + } + }, + + rerenderContainingView: function() { + var self = this; + Ember.run.scheduleOnce('render', this, function() { + // It's possible it's been destroyed after we enqueued a re-render call. + if (!self.destroyed) { + self.containingView.rerender(); + } + }); + }, + + destroy: function() { + this.removeContentObservers(); + if (this.content) { + this.removeArrayObservers(); + } + this.destroyed = true; + } +}; + +/** + The `{{#each}}` helper loops over elements in a collection, rendering its + block once for each item. It is an extension of the base Handlebars `{{#each}}` + helper: + + ```javascript + Developers = [{name: 'Yehuda'},{name: 'Tom'}, {name: 'Paul'}]; + ``` + + ```handlebars + {{#each Developers}} + {{name}} + {{/each}} + ``` + + `{{each}}` supports an alternative syntax with element naming: + + ```handlebars + {{#each person in Developers}} + {{person.name}} + {{/each}} + ``` + + When looping over objects that do not have properties, `{{this}}` can be used + to render the object: + + ```javascript + DeveloperNames = ['Yehuda', 'Tom', 'Paul'] + ``` + + ```handlebars + {{#each DeveloperNames}} + {{this}} + {{/each}} + ``` + ### {{else}} condition + `{{#each}}` can have a matching `{{else}}`. The contents of this block will render + if the collection is empty. + + ``` + {{#each person in Developers}} + {{person.name}} + {{else}} +

    Sorry, nobody is available for this task.

    + {{/each}} + ``` + ### Specifying a View class for items + If you provide an `itemViewClass` option that references a view class + with its own `template` you can omit the block. + + The following template: + + ```handlebars + {{#view App.MyView }} + {{each view.items itemViewClass="App.AnItemView"}} + {{/view}} + ``` + + And application code + + ```javascript + App = Ember.Application.create({ + MyView: Ember.View.extend({ + items: [ + Ember.Object.create({name: 'Dave'}), + Ember.Object.create({name: 'Mary'}), + Ember.Object.create({name: 'Sara'}) + ] + }) + }); + + App.AnItemView = Ember.View.extend({ + template: Ember.Handlebars.compile("Greetings {{name}}") + }); + ``` + + Will result in the HTML structure below + + ```html +
    +
    Greetings Dave
    +
    Greetings Mary
    +
    Greetings Sara
    +
    + ``` + + If an `itemViewClass` is defined on the helper, and therefore the helper is not + being used as a block, an `emptyViewClass` can also be provided optionally. + The `emptyViewClass` will match the behavior of the `{{else}}` condition + described above. That is, the `emptyViewClass` will render if the collection + is empty. + + ### Representing each item with a Controller. + By default the controller lookup within an `{{#each}}` block will be + the controller of the template where the `{{#each}}` was used. If each + item needs to be presented by a custom controller you can provide a + `itemController` option which references a controller by lookup name. + Each item in the loop will be wrapped in an instance of this controller + and the item itself will be set to the `content` property of that controller. + + This is useful in cases where properties of model objects need transformation + or synthesis for display: + + ```javascript + App.DeveloperController = Ember.ObjectController.extend({ + isAvailableForHire: function() { + return !this.get('content.isEmployed') && this.get('content.isSeekingWork'); + }.property('isEmployed', 'isSeekingWork') + }) + ``` + + ```handlebars + {{#each person in developers itemController="developer"}} + {{person.name}} {{#if person.isAvailableForHire}}Hire me!{{/if}} + {{/each}} + ``` + + Each itemController will receive a reference to the current controller as + a `parentController` property. + + ### (Experimental) Grouped Each + + When used in conjunction with the experimental [group helper](https://github.com/emberjs/group-helper), + you can inform Handlebars to re-render an entire group of items instead of + re-rendering them one at a time (in the event that they are changed en masse + or an item is added/removed). + + ```handlebars + {{#group}} + {{#each people}} + {{firstName}} {{lastName}} + {{/each}} + {{/group}} + ``` + + This can be faster than the normal way that Handlebars re-renders items + in some cases. + + If for some reason you have a group with more than one `#each`, you can make + one of the collections be updated in normal (non-grouped) fashion by setting + the option `groupedRows=true` (counter-intuitive, I know). + + For example, + + ```handlebars + {{dealershipName}} + + {{#group}} + {{#each dealers}} + {{firstName}} {{lastName}} + {{/each}} + + {{#each car in cars groupedRows=true}} + {{car.make}} {{car.model}} {{car.color}} + {{/each}} + {{/group}} + ``` + Any change to `dealershipName` or the `dealers` collection will cause the + entire group to be re-rendered. However, changes to the `cars` collection + will be re-rendered individually (as normal). + + Note that `group` behavior is also disabled by specifying an `itemViewClass`. + + @method each + @for Ember.Handlebars.helpers + @param [name] {String} name for item (used with `in`) + @param [path] {String} path + @param [options] {Object} Handlebars key/value pairs of options + @param [options.itemViewClass] {String} a path to a view class used for each item + @param [options.itemController] {String} name of a controller to be created for each item + @param [options.groupedRows] {boolean} enable normal item-by-item rendering when inside a `#group` helper +*/ +Ember.Handlebars.registerHelper('each', function(path, options) { + if (arguments.length === 4) { + Ember.assert("If you pass more than one argument to the each helper, it must be in the form #each foo in bar", arguments[1] === "in"); + + var keywordName = arguments[0]; + + options = arguments[3]; + path = arguments[2]; + if (path === '') { path = "this"; } + + options.hash.keyword = keywordName; + } + + if (arguments.length === 1) { + options = path; + path = 'this'; + } + + options.hash.dataSourceBinding = path; + // Set up emptyView as a metamorph with no tag + //options.hash.emptyViewClass = Ember._MetamorphView; + + if (options.data.insideGroup && !options.hash.groupedRows && !options.hash.itemViewClass) { + new Ember.Handlebars.GroupedEach(this, path, options).render(); + } else { + return Ember.Handlebars.helpers.collection.call(this, 'Ember.Handlebars.EachView', options); + } +}); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-handlebars +*/ + +/** + `template` allows you to render a template from inside another template. + This allows you to re-use the same template in multiple places. For example: + + ```html + + ``` + + ```html + + ``` + + ```handlebars + {{#if isUser}} + {{template "user_info"}} + {{else}} + {{template "unlogged_user_info"}} + {{/if}} + ``` + + This helper looks for templates in the global `Ember.TEMPLATES` hash. If you + add ` + ``` + + Take note that `"welcome"` is a string and not an object + reference. + + @method loc + @for Ember.Handlebars.helpers + @param {String} str The string to format +*/ + +Ember.Handlebars.registerHelper('loc', function(str) { + return Ember.String.loc(str); +}); + +})(); + + + +(function() { + +})(); + + + +(function() { + +})(); + + + +(function() { +/** +@module ember +@submodule ember-handlebars +*/ + +var set = Ember.set, get = Ember.get; + +/** + The internal class used to create text inputs when the `{{input}}` + helper is used with `type` of `checkbox`. + + See Handlebars.helpers.input for usage details. + + ## Direct manipulation of `checked` + + The `checked` attribute of an `Ember.Checkbox` object should always be set + through the Ember object or by interacting with its rendered element + representation via the mouse, keyboard, or touch. Updating the value of the + checkbox via jQuery will result in the checked value of the object and its + element losing synchronization. + + ## Layout and LayoutName properties + + Because HTML `input` elements are self closing `layout` and `layoutName` + properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s + layout section for more information. + + @class Checkbox + @namespace Ember + @extends Ember.View +*/ +Ember.Checkbox = Ember.View.extend({ + classNames: ['ember-checkbox'], + + tagName: 'input', + + attributeBindings: ['type', 'checked', 'indeterminate', 'disabled', 'tabindex', 'name'], + + type: "checkbox", + checked: false, + disabled: false, + indeterminate: false, + + init: function() { + this._super(); + this.on("change", this, this._updateElementValue); + }, + + didInsertElement: function() { + this._super(); + this.get('element').indeterminate = !!this.get('indeterminate'); + }, + + _updateElementValue: function() { + set(this, 'checked', this.$().prop('checked')); + } +}); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-handlebars +*/ + +var get = Ember.get, set = Ember.set; + +/** + Shared mixin used by `Ember.TextField` and `Ember.TextArea`. + + @class TextSupport + @namespace Ember + @private +*/ +Ember.TextSupport = Ember.Mixin.create({ + value: "", + + attributeBindings: ['placeholder', 'disabled', 'maxlength', 'tabindex', 'readonly'], + placeholder: null, + disabled: false, + maxlength: null, + + init: function() { + this._super(); + this.on("focusOut", this, this._elementValueDidChange); + this.on("change", this, this._elementValueDidChange); + this.on("paste", this, this._elementValueDidChange); + this.on("cut", this, this._elementValueDidChange); + this.on("input", this, this._elementValueDidChange); + this.on("keyUp", this, this.interpretKeyEvents); + }, + + /** + The action to be sent when the user presses the return key. + + This is similar to the `{{action}}` helper, but is fired when + the user presses the return key when editing a text field, and sends + the value of the field as the context. + + @property action + @type String + @default null + */ + action: null, + + /** + The event that should send the action. + + Options are: + + * `enter`: the user pressed enter + * `keyPress`: the user pressed a key + + @property onEvent + @type String + @default enter + */ + onEvent: 'enter', + + /** + Whether they `keyUp` event that triggers an `action` to be sent continues + propagating to other views. + + By default, when the user presses the return key on their keyboard and + the text field has an `action` set, the action will be sent to the view's + controller and the key event will stop propagating. + + If you would like parent views to receive the `keyUp` event even after an + action has been dispatched, set `bubbles` to true. + + @property bubbles + @type Boolean + @default false + */ + bubbles: false, + + interpretKeyEvents: function(event) { + var map = Ember.TextSupport.KEY_EVENTS; + var method = map[event.keyCode]; + + this._elementValueDidChange(); + if (method) { return this[method](event); } + }, + + _elementValueDidChange: function() { + set(this, 'value', this.$().val()); + }, + + /** + The action to be sent when the user inserts a new line. + + Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 13. + Uses sendAction to send the `enter` action to the controller. + + @method insertNewline + @param {Event} event + */ + insertNewline: function(event) { + sendAction('enter', this, event); + sendAction('insert-newline', this, event); + }, + + /** + Called when the user hits escape. + + Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 27. + Uses sendAction to send the `escape-press` action to the controller. + + @method cancel + @param {Event} event + */ + cancel: function(event) { + sendAction('escape-press', this, event); + }, + + /** + Called when the text area is focused. + + @method focusIn + @param {Event} event + */ + focusIn: function(event) { + sendAction('focus-in', this, event); + }, + + /** + Called when the text area is blurred. + + @method focusOut + @param {Event} event + */ + focusOut: function(event) { + sendAction('focus-out', this, event); + }, + + /** + The action to be sent when the user presses a key. Enabled by setting + the `onEvent` property to `keyPress`. + + Uses sendAction to send the `keyPress` action to the controller. + + @method keyPress + @param {Event} event + */ + keyPress: function(event) { + sendAction('key-press', this, event); + } + +}); + +Ember.TextSupport.KEY_EVENTS = { + 13: 'insertNewline', + 27: 'cancel' +}; + +// In principle, this shouldn't be necessary, but the legacy +// sectionAction semantics for TextField are different from +// the component semantics so this method normalizes them. +function sendAction(eventName, view, event) { + var action = get(view, eventName), + on = get(view, 'onEvent'), + value = get(view, 'value'); + + // back-compat support for keyPress as an event name even though + // it's also a method name that consumes the event (and therefore + // incompatible with sendAction semantics). + if (on === eventName || (on === 'keyPress' && eventName === 'key-press')) { + view.sendAction('action', value); + } + + view.sendAction(eventName, value); + + if (action || on === eventName) { + if(!get(view, 'bubbles')) { + event.stopPropagation(); + } + } +} + +})(); + + + +(function() { +/** +@module ember +@submodule ember-handlebars +*/ + +var get = Ember.get, set = Ember.set; + +/** + + The internal class used to create text inputs when the `{{input}}` + helper is used with `type` of `text`. + + See [handlebars.helpers.input](Ember.Handlebars.helpers.html#method_input) for usage details. + + ## Layout and LayoutName properties + + Because HTML `input` elements are self closing `layout` and `layoutName` + properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s + layout section for more information. + + @class TextField + @namespace Ember + @extends Ember.Component + @uses Ember.TextSupport +*/ +Ember.TextField = Ember.Component.extend(Ember.TextSupport, + /** @scope Ember.TextField.prototype */ { + + classNames: ['ember-text-field'], + tagName: "input", + attributeBindings: ['type', 'value', 'size', 'pattern', 'name'], + + /** + The `value` attribute of the input element. As the user inputs text, this + property is updated live. + + @property value + @type String + @default "" + */ + value: "", + + /** + The `type` attribute of the input element. + + @property type + @type String + @default "text" + */ + type: "text", + + /** + The `size` of the text field in characters. + + @property size + @type String + @default null + */ + size: null, + + /** + The `pattern` the pattern attribute of input element. + + @property pattern + @type String + @default null + */ + pattern: null +}); + +})(); + + + +(function() { +/* +@module ember +@submodule ember-handlebars +*/ + +var get = Ember.get, set = Ember.set; + +/* + @class Button + @namespace Ember + @extends Ember.View + @uses Ember.TargetActionSupport + @deprecated +*/ +Ember.Button = Ember.View.extend(Ember.TargetActionSupport, { + classNames: ['ember-button'], + classNameBindings: ['isActive'], + + tagName: 'button', + + propagateEvents: false, + + attributeBindings: ['type', 'disabled', 'href', 'tabindex'], + + /* + @private + + Overrides `TargetActionSupport`'s `targetObject` computed + property to use Handlebars-specific path resolution. + + @property targetObject + */ + targetObject: Ember.computed(function() { + var target = get(this, 'target'), + root = get(this, 'context'), + data = get(this, 'templateData'); + + if (typeof target !== 'string') { return target; } + + return Ember.Handlebars.get(root, target, { data: data }); + }).property('target'), + + // Defaults to 'button' if tagName is 'input' or 'button' + type: Ember.computed(function(key) { + var tagName = this.tagName; + if (tagName === 'input' || tagName === 'button') { return 'button'; } + }), + + disabled: false, + + // Allow 'a' tags to act like buttons + href: Ember.computed(function() { + return this.tagName === 'a' ? '#' : null; + }), + + mouseDown: function() { + if (!get(this, 'disabled')) { + set(this, 'isActive', true); + this._mouseDown = true; + this._mouseEntered = true; + } + return get(this, 'propagateEvents'); + }, + + mouseLeave: function() { + if (this._mouseDown) { + set(this, 'isActive', false); + this._mouseEntered = false; + } + }, + + mouseEnter: function() { + if (this._mouseDown) { + set(this, 'isActive', true); + this._mouseEntered = true; + } + }, + + mouseUp: function(event) { + if (get(this, 'isActive')) { + // Actually invoke the button's target and action. + // This method comes from the Ember.TargetActionSupport mixin. + this.triggerAction(); + set(this, 'isActive', false); + } + + this._mouseDown = false; + this._mouseEntered = false; + return get(this, 'propagateEvents'); + }, + + keyDown: function(event) { + // Handle space or enter + if (event.keyCode === 13 || event.keyCode === 32) { + this.mouseDown(); + } + }, + + keyUp: function(event) { + // Handle space or enter + if (event.keyCode === 13 || event.keyCode === 32) { + this.mouseUp(); + } + }, + + // TODO: Handle proper touch behavior. Including should make inactive when + // finger moves more than 20x outside of the edge of the button (vs mouse + // which goes inactive as soon as mouse goes out of edges.) + + touchStart: function(touch) { + return this.mouseDown(touch); + }, + + touchEnd: function(touch) { + return this.mouseUp(touch); + }, + + init: function() { + Ember.deprecate("Ember.Button is deprecated and will be removed from future releases. Consider using the `{{action}}` helper."); + this._super(); + } +}); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-handlebars +*/ + +var get = Ember.get, set = Ember.set; + +/** + The internal class used to create textarea element when the `{{textarea}}` + helper is used. + + See [handlebars.helpers.textarea](/api/classes/Ember.Handlebars.helpers.html#method_textarea) for usage details. + + ## Layout and LayoutName properties + + Because HTML `textarea` elements do not contain inner HTML the `layout` and + `layoutName` properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s + layout section for more information. + + @class TextArea + @namespace Ember + @extends Ember.Component + @uses Ember.TextSupport +*/ +Ember.TextArea = Ember.Component.extend(Ember.TextSupport, { + classNames: ['ember-text-area'], + + tagName: "textarea", + attributeBindings: ['rows', 'cols', 'name'], + rows: null, + cols: null, + + _updateElementValue: Ember.observer('value', function() { + // We do this check so cursor position doesn't get affected in IE + var value = get(this, 'value'), + $el = this.$(); + if ($el && value !== $el.val()) { + $el.val(value); + } + }), + + init: function() { + this._super(); + this.on("didInsertElement", this, this._updateElementValue); + } + +}); + +})(); + + + +(function() { +/*jshint eqeqeq:false */ + +/** +@module ember +@submodule ember-handlebars +*/ + +var set = Ember.set, + get = Ember.get, + indexOf = Ember.EnumerableUtils.indexOf, + indexesOf = Ember.EnumerableUtils.indexesOf, + forEach = Ember.EnumerableUtils.forEach, + replace = Ember.EnumerableUtils.replace, + isArray = Ember.isArray, + precompileTemplate = Ember.Handlebars.compile; + +Ember.SelectOption = Ember.View.extend({ + tagName: 'option', + attributeBindings: ['value', 'selected'], + + defaultTemplate: function(context, options) { + options = { data: options.data, hash: {} }; + Ember.Handlebars.helpers.bind.call(context, "view.label", options); + }, + + init: function() { + this.labelPathDidChange(); + this.valuePathDidChange(); + + this._super(); + }, + + selected: Ember.computed(function() { + var content = get(this, 'content'), + selection = get(this, 'parentView.selection'); + if (get(this, 'parentView.multiple')) { + return selection && indexOf(selection, content.valueOf()) > -1; + } else { + // Primitives get passed through bindings as objects... since + // `new Number(4) !== 4`, we use `==` below + return content == selection; + } + }).property('content', 'parentView.selection'), + + labelPathDidChange: Ember.observer('parentView.optionLabelPath', function() { + var labelPath = get(this, 'parentView.optionLabelPath'); + + if (!labelPath) { return; } + + Ember.defineProperty(this, 'label', Ember.computed(function() { + return get(this, labelPath); + }).property(labelPath)); + }), + + valuePathDidChange: Ember.observer('parentView.optionValuePath', function() { + var valuePath = get(this, 'parentView.optionValuePath'); + + if (!valuePath) { return; } + + Ember.defineProperty(this, 'value', Ember.computed(function() { + return get(this, valuePath); + }).property(valuePath)); + }) +}); + +Ember.SelectOptgroup = Ember.CollectionView.extend({ + tagName: 'optgroup', + attributeBindings: ['label'], + + selectionBinding: 'parentView.selection', + multipleBinding: 'parentView.multiple', + optionLabelPathBinding: 'parentView.optionLabelPath', + optionValuePathBinding: 'parentView.optionValuePath', + + itemViewClassBinding: 'parentView.optionView' +}); + +/** + The `Ember.Select` view class renders a + [select](https://developer.mozilla.org/en/HTML/Element/select) HTML element, + allowing the user to choose from a list of options. + + The text and `value` property of each ` + + + ``` + + The `value` attribute of the selected `"); + return buffer; + } + +function program3(depth0,data) { + + var stack1, hashTypes, hashContexts; + hashTypes = {}; + hashContexts = {}; + stack1 = helpers.each.call(depth0, "view.groupedContent", {hash:{},inverse:self.noop,fn:self.program(4, program4, data),contexts:[depth0],types:["ID"],hashContexts:hashContexts,hashTypes:hashTypes,data:data}); + if(stack1 || stack1 === 0) { data.buffer.push(stack1); } + else { data.buffer.push(''); } + } +function program4(depth0,data) { + + var hashContexts, hashTypes; + hashContexts = {'content': depth0,'label': depth0}; + hashTypes = {'content': "ID",'label': "ID"}; + data.buffer.push(escapeExpression(helpers.view.call(depth0, "view.groupView", {hash:{ + 'content': ("content"), + 'label': ("label") + },contexts:[depth0],types:["ID"],hashContexts:hashContexts,hashTypes:hashTypes,data:data}))); + } + +function program6(depth0,data) { + + var stack1, hashTypes, hashContexts; + hashTypes = {}; + hashContexts = {}; + stack1 = helpers.each.call(depth0, "view.content", {hash:{},inverse:self.noop,fn:self.program(7, program7, data),contexts:[depth0],types:["ID"],hashContexts:hashContexts,hashTypes:hashTypes,data:data}); + if(stack1 || stack1 === 0) { data.buffer.push(stack1); } + else { data.buffer.push(''); } + } +function program7(depth0,data) { + + var hashContexts, hashTypes; + hashContexts = {'content': depth0}; + hashTypes = {'content': "ID"}; + data.buffer.push(escapeExpression(helpers.view.call(depth0, "view.optionView", {hash:{ + 'content': ("") + },contexts:[depth0],types:["ID"],hashContexts:hashContexts,hashTypes:hashTypes,data:data}))); + } + + hashTypes = {}; + hashContexts = {}; + stack1 = helpers['if'].call(depth0, "view.prompt", {hash:{},inverse:self.noop,fn:self.program(1, program1, data),contexts:[depth0],types:["ID"],hashContexts:hashContexts,hashTypes:hashTypes,data:data}); + if(stack1 || stack1 === 0) { data.buffer.push(stack1); } + hashTypes = {}; + hashContexts = {}; + stack1 = helpers['if'].call(depth0, "view.optionGroupPath", {hash:{},inverse:self.program(6, program6, data),fn:self.program(3, program3, data),contexts:[depth0],types:["ID"],hashContexts:hashContexts,hashTypes:hashTypes,data:data}); + if(stack1 || stack1 === 0) { data.buffer.push(stack1); } + return buffer; + +}), + attributeBindings: ['multiple', 'disabled', 'tabindex', 'name'], + + /** + The `multiple` attribute of the select element. Indicates whether multiple + options can be selected. + + @property multiple + @type Boolean + @default false + */ + multiple: false, + + /** + The `disabled` attribute of the select element. Indicates whether + the element is disabled from interactions. + + @property disabled + @type Boolean + @default false + */ + disabled: false, + + /** + The list of options. + + If `optionLabelPath` and `optionValuePath` are not overridden, this should + be a list of strings, which will serve simultaneously as labels and values. + + Otherwise, this should be a list of objects. For instance: + + ```javascript + Ember.Select.create({ + content: Ember.A([ + { id: 1, firstName: 'Yehuda' }, + { id: 2, firstName: 'Tom' } + ]), + optionLabelPath: 'content.firstName', + optionValuePath: 'content.id' + }); + ``` + + @property content + @type Array + @default null + */ + content: null, + + /** + When `multiple` is `false`, the element of `content` that is currently + selected, if any. + + When `multiple` is `true`, an array of such elements. + + @property selection + @type Object or Array + @default null + */ + selection: null, + + /** + In single selection mode (when `multiple` is `false`), value can be used to + get the current selection's value or set the selection by it's value. + + It is not currently supported in multiple selection mode. + + @property value + @type String + @default null + */ + value: Ember.computed(function(key, value) { + if (arguments.length === 2) { return value; } + var valuePath = get(this, 'optionValuePath').replace(/^content\.?/, ''); + return valuePath ? get(this, 'selection.' + valuePath) : get(this, 'selection'); + }).property('selection'), + + /** + If given, a top-most dummy option will be rendered to serve as a user + prompt. + + @property prompt + @type String + @default null + */ + prompt: null, + + /** + The path of the option labels. See [content](/api/classes/Ember.Select.html#property_content). + + @property optionLabelPath + @type String + @default 'content' + */ + optionLabelPath: 'content', + + /** + The path of the option values. See [content](/api/classes/Ember.Select.html#property_content). + + @property optionValuePath + @type String + @default 'content' + */ + optionValuePath: 'content', + + /** + The path of the option group. + When this property is used, `content` should be sorted by `optionGroupPath`. + + @property optionGroupPath + @type String + @default null + */ + optionGroupPath: null, + + /** + The view class for optgroup. + + @property groupView + @type Ember.View + @default Ember.SelectOptgroup + */ + groupView: Ember.SelectOptgroup, + + groupedContent: Ember.computed(function() { + var groupPath = get(this, 'optionGroupPath'); + var groupedContent = Ember.A(); + var content = get(this, 'content') || []; + + forEach(content, function(item) { + var label = get(item, groupPath); + + if (get(groupedContent, 'lastObject.label') !== label) { + groupedContent.pushObject({ + label: label, + content: Ember.A() + }); + } + + get(groupedContent, 'lastObject.content').push(item); + }); + + return groupedContent; + }).property('optionGroupPath', 'content.@each'), + + /** + The view class for option. + + @property optionView + @type Ember.View + @default Ember.SelectOption + */ + optionView: Ember.SelectOption, + + _change: function() { + if (get(this, 'multiple')) { + this._changeMultiple(); + } else { + this._changeSingle(); + } + }, + + selectionDidChange: Ember.observer('selection.@each', function() { + var selection = get(this, 'selection'); + if (get(this, 'multiple')) { + if (!isArray(selection)) { + set(this, 'selection', Ember.A([selection])); + return; + } + this._selectionDidChangeMultiple(); + } else { + this._selectionDidChangeSingle(); + } + }), + + valueDidChange: Ember.observer('value', function() { + var content = get(this, 'content'), + value = get(this, 'value'), + valuePath = get(this, 'optionValuePath').replace(/^content\.?/, ''), + selectedValue = (valuePath ? get(this, 'selection.' + valuePath) : get(this, 'selection')), + selection; + + if (value !== selectedValue) { + selection = content ? content.find(function(obj) { + return value === (valuePath ? get(obj, valuePath) : obj); + }) : null; + + this.set('selection', selection); + } + }), + + + _triggerChange: function() { + var selection = get(this, 'selection'); + var value = get(this, 'value'); + + if (!Ember.isNone(selection)) { this.selectionDidChange(); } + if (!Ember.isNone(value)) { this.valueDidChange(); } + + this._change(); + }, + + _changeSingle: function() { + var selectedIndex = this.$()[0].selectedIndex, + content = get(this, 'content'), + prompt = get(this, 'prompt'); + + if (!content || !get(content, 'length')) { return; } + if (prompt && selectedIndex === 0) { set(this, 'selection', null); return; } + + if (prompt) { selectedIndex -= 1; } + set(this, 'selection', content.objectAt(selectedIndex)); + }, + + + _changeMultiple: function() { + var options = this.$('option:selected'), + prompt = get(this, 'prompt'), + offset = prompt ? 1 : 0, + content = get(this, 'content'), + selection = get(this, 'selection'); + + if (!content) { return; } + if (options) { + var selectedIndexes = options.map(function() { + return this.index - offset; + }).toArray(); + var newSelection = content.objectsAt(selectedIndexes); + + if (isArray(selection)) { + replace(selection, 0, get(selection, 'length'), newSelection); + } else { + set(this, 'selection', newSelection); + } + } + }, + + _selectionDidChangeSingle: function() { + var el = this.get('element'); + if (!el) { return; } + + var content = get(this, 'content'), + selection = get(this, 'selection'), + selectionIndex = content ? indexOf(content, selection) : -1, + prompt = get(this, 'prompt'); + + if (prompt) { selectionIndex += 1; } + if (el) { el.selectedIndex = selectionIndex; } + }, + + _selectionDidChangeMultiple: function() { + var content = get(this, 'content'), + selection = get(this, 'selection'), + selectedIndexes = content ? indexesOf(content, selection) : [-1], + prompt = get(this, 'prompt'), + offset = prompt ? 1 : 0, + options = this.$('option'), + adjusted; + + if (options) { + options.each(function() { + adjusted = this.index > -1 ? this.index - offset : -1; + this.selected = indexOf(selectedIndexes, adjusted) > -1; + }); + } + }, + + init: function() { + this._super(); + this.on("didInsertElement", this, this._triggerChange); + this.on("change", this, this._change); + } +}); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-handlebars-compiler +*/ + +/** + + The `{{input}}` helper inserts an HTML `` tag into the template, + with a `type` value of either `text` or `checkbox`. If no `type` is provided, + `text` will be the default value applied. The attributes of `{{input}}` + match those of the native HTML tag as closely as possible for these two types. + + ## Use as text field + An `{{input}}` with no `type` or a `type` of `text` will render an HTML text input. + The following HTML attributes can be set via the helper: + +* `value` +* `size` +* `name` +* `pattern` +* `placeholder` +* `disabled` +* `maxlength` +* `tabindex` + + + When set to a quoted string, these values will be directly applied to the HTML + element. When left unquoted, these values will be bound to a property on the + template's current rendering context (most typically a controller instance). + + ## Unbound: + + ```handlebars + {{input value="http://www.facebook.com"}} + ``` + + + ```html + + ``` + + ## Bound: + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + firstName: "Stanley", + entryNotAllowed: true + }); + ``` + + + ```handlebars + {{input type="text" value=firstName disabled=entryNotAllowed size="50"}} + ``` + + + ```html + + ``` + + ## Extension + + Internally, `{{input type="text"}}` creates an instance of `Ember.TextField`, passing + arguments from the helper to `Ember.TextField`'s `create` method. You can extend the + capablilties of text inputs in your applications by reopening this class. For example, + if you are deploying to browsers where the `required` attribute is used, you + can add this to the `TextField`'s `attributeBindings` property: + + ```javascript + Ember.TextField.reopen({ + attributeBindings: ['required'] + }); + ``` + + Keep in mind when writing `Ember.TextField` subclasses that `Ember.TextField` + itself extends `Ember.Component`, meaning that it does NOT inherit + the `controller` of the parent view. + + See more about [Ember components](api/classes/Ember.Component.html) + + + ## Use as checkbox + + An `{{input}}` with a `type` of `checkbox` will render an HTML checkbox input. + The following HTML attributes can be set via the helper: + +* `checked` +* `disabled` +* `tabindex` +* `indeterminate` +* `name` + + + When set to a quoted string, these values will be directly applied to the HTML + element. When left unquoted, these values will be bound to a property on the + template's current rendering context (most typically a controller instance). + + ## Unbound: + + ```handlebars + {{input type="checkbox" name="isAdmin"}} + ``` + + ```html + + ``` + + ## Bound: + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + isAdmin: true + }); + ``` + + + ```handlebars + {{input type="checkbox" checked=isAdmin }} + ``` + + + ```html + + ``` + + ## Extension + + Internally, `{{input type="checkbox"}}` creates an instance of `Ember.Checkbox`, passing + arguments from the helper to `Ember.Checkbox`'s `create` method. You can extend the + capablilties of checkbox inputs in your applications by reopening this class. For example, + if you wanted to add a css class to all checkboxes in your application: + + ```javascript + Ember.Checkbox.reopen({ + classNames: ['my-app-checkbox'] + }); + ``` + + + @method input + @for Ember.Handlebars.helpers + @param {Hash} options +*/ +Ember.Handlebars.registerHelper('input', function(options) { + Ember.assert('You can only pass attributes to the `input` helper, not arguments', arguments.length < 2); + + var hash = options.hash, + types = options.hashTypes, + inputType = hash.type, + onEvent = hash.on; + + delete hash.type; + delete hash.on; + + if (inputType === 'checkbox') { + return Ember.Handlebars.helpers.view.call(this, Ember.Checkbox, options); + } else { + if (inputType) { hash.type = inputType; } + hash.onEvent = onEvent || 'enter'; + return Ember.Handlebars.helpers.view.call(this, Ember.TextField, options); + } +}); + +/** + `{{textarea}}` inserts a new instance of ` + ``` + + Bound: + + In the following example, the `writtenWords` property on `App.ApplicationController` + will be updated live as the user types 'Lots of text that IS bound' into + the text area of their browser's window. + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + writtenWords: "Lots of text that IS bound" + }); + ``` + + ```handlebars + {{textarea value=writtenWords}} + ``` + + Would result in the following HTML: + + ```html + + ``` + + If you wanted a one way binding between the text area and a div tag + somewhere else on your screen, you could use `Ember.computed.oneWay`: + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + writtenWords: "Lots of text that IS bound", + outputWrittenWords: Ember.computed.oneWay("writtenWords") + }); + ``` + + ```handlebars + {{textarea value=writtenWords}} + +
    + {{outputWrittenWords}} +
    + ``` + + Would result in the following HTML: + + ```html + + + <-- the following div will be updated in real time as you type --> + +
    + Lots of text that IS bound +
    + ``` + + Finally, this example really shows the power and ease of Ember when two + properties are bound to eachother via `Ember.computed.alias`. Type into + either text area box and they'll both stay in sync. Note that + `Ember.computed.alias` costs more in terms of performance, so only use it when + your really binding in both directions: + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + writtenWords: "Lots of text that IS bound", + twoWayWrittenWords: Ember.computed.alias("writtenWords") + }); + ``` + + ```handlebars + {{textarea value=writtenWords}} + {{textarea value=twoWayWrittenWords}} + ``` + + ```html + + + <-- both updated in real time --> + + + ``` + + ## Extension + + Internally, `{{textarea}}` creates an instance of `Ember.TextArea`, passing + arguments from the helper to `Ember.TextArea`'s `create` method. You can + extend the capabilities of text areas in your application by reopening this + class. For example, if you are deploying to browsers where the `required` + attribute is used, you can globally add support for the `required` attribute + on all {{textarea}}'s' in your app by reopening `Ember.TextArea` or + `Ember.TextSupport` and adding it to the `attributeBindings` concatenated + property: + + ```javascript + Ember.TextArea.reopen({ + attributeBindings: ['required'] + }); + ``` + + Keep in mind when writing `Ember.TextArea` subclasses that `Ember.TextArea` + itself extends `Ember.Component`, meaning that it does NOT inherit + the `controller` of the parent view. + + See more about [Ember components](api/classes/Ember.Component.html) + + @method textarea + @for Ember.Handlebars.helpers + @param {Hash} options +*/ +Ember.Handlebars.registerHelper('textarea', function(options) { + Ember.assert('You can only pass attributes to the `textarea` helper, not arguments', arguments.length < 2); + + var hash = options.hash, + types = options.hashTypes; + + return Ember.Handlebars.helpers.view.call(this, Ember.TextArea, options); +}); + +})(); + + + +(function() { +Ember.ComponentLookup = Ember.Object.extend({ + lookupFactory: function(name, container) { + + container = container || this.container; + + var fullName = 'component:' + name, + templateFullName = 'template:components/' + name, + templateRegistered = container && container.has(templateFullName); + + if (templateRegistered) { + container.injection(fullName, 'layout', templateFullName); + } + + var Component = container.lookupFactory(fullName); + + // Only treat as a component if either the component + // or a template has been registered. + if (templateRegistered || Component) { + if (!Component) { + container.register(fullName, Ember.Component); + Component = container.lookupFactory(fullName); + } + return Component; + } + } +}); + +})(); + + + +(function() { +/*globals Handlebars */ +/** +@module ember +@submodule ember-handlebars +*/ + +/** + @private + + Find templates stored in the head tag as script tags and make them available + to `Ember.CoreView` in the global `Ember.TEMPLATES` object. This will be run + as as jQuery DOM-ready callback. + + Script tags with `text/x-handlebars` will be compiled + with Ember's Handlebars and are suitable for use as a view's template. + Those with type `text/x-raw-handlebars` will be compiled with regular + Handlebars and are suitable for use in views' computed properties. + + @method bootstrap + @for Ember.Handlebars + @static + @param ctx +*/ +Ember.Handlebars.bootstrap = function(ctx) { + var selectors = 'script[type="text/x-handlebars"], script[type="text/x-raw-handlebars"]'; + + Ember.$(selectors, ctx) + .each(function() { + // Get a reference to the script tag + var script = Ember.$(this); + + var compile = (script.attr('type') === 'text/x-raw-handlebars') ? + Ember.$.proxy(Handlebars.compile, Handlebars) : + Ember.$.proxy(Ember.Handlebars.compile, Ember.Handlebars), + // Get the name of the script, used by Ember.View's templateName property. + // First look for data-template-name attribute, then fall back to its + // id if no name is found. + templateName = script.attr('data-template-name') || script.attr('id') || 'application', + template = compile(script.html()); + + // Check if template of same name already exists + if (Ember.TEMPLATES[templateName] !== undefined) { + throw new Ember.Error('Template named "' + templateName + '" already exists.'); + } + + // For templates which have a name, we save them and then remove them from the DOM + Ember.TEMPLATES[templateName] = template; + + // Remove script tag from DOM + script.remove(); + }); +}; + +function bootstrap() { + Ember.Handlebars.bootstrap( Ember.$(document) ); +} + +function registerComponents(container) { + var templates = Ember.TEMPLATES, match; + if (!templates) { return; } + + for (var prop in templates) { + if (match = prop.match(/^components\/(.*)$/)) { + registerComponent(container, match[1]); + } + } +} + + +function registerComponent(container, name) { + Ember.assert("You provided a template named 'components/" + name + "', but custom components must include a '-'", name.match(/-/)); + + var fullName = 'component:' + name; + + container.injection(fullName, 'layout', 'template:components/' + name); + + var Component = container.lookupFactory(fullName); + + if (!Component) { + container.register(fullName, Ember.Component); + Component = container.lookupFactory(fullName); + } + + Ember.Handlebars.helper(name, Component); +} + +function registerComponentLookup(container) { + container.register('component-lookup:main', Ember.ComponentLookup); +} + +/* + We tie this to application.load to ensure that we've at least + attempted to bootstrap at the point that the application is loaded. + + We also tie this to document ready since we're guaranteed that all + the inline templates are present at this point. + + There's no harm to running this twice, since we remove the templates + from the DOM after processing. +*/ + +Ember.onLoad('Ember.Application', function(Application) { + Application.initializer({ + name: 'domTemplates', + initialize: bootstrap + }); + + + Application.initializer({ + name: 'registerComponentLookup', + after: 'domTemplates', + initialize: registerComponentLookup + }); + }); + +})(); + + + +(function() { +/** +Ember Handlebars + +@module ember +@submodule ember-handlebars +@requires ember-views +*/ + +Ember.runLoadHooks('Ember.Handlebars', Ember.Handlebars); + +})(); + +(function() { +define("route-recognizer", + [], + function() { + "use strict"; + var specials = [ + '/', '.', '*', '+', '?', '|', + '(', ')', '[', ']', '{', '}', '\\' + ]; + + var escapeRegex = new RegExp('(\\' + specials.join('|\\') + ')', 'g'); + + // A Segment represents a segment in the original route description. + // Each Segment type provides an `eachChar` and `regex` method. + // + // The `eachChar` method invokes the callback with one or more character + // specifications. A character specification consumes one or more input + // characters. + // + // The `regex` method returns a regex fragment for the segment. If the + // segment is a dynamic of star segment, the regex fragment also includes + // a capture. + // + // A character specification contains: + // + // * `validChars`: a String with a list of all valid characters, or + // * `invalidChars`: a String with a list of all invalid characters + // * `repeat`: true if the character specification can repeat + + function StaticSegment(string) { this.string = string; } + StaticSegment.prototype = { + eachChar: function(callback) { + var string = this.string, char; + + for (var i=0, l=string.length; i " + n.nextStates.map(function(s) { return s.debug() }).join(" or ") + " )"; + }).join(", ") + } + END IF **/ + + // This is a somewhat naive strategy, but should work in a lot of cases + // A better strategy would properly resolve /posts/:id/new and /posts/edit/:id + function sortSolutions(states) { + return states.sort(function(a, b) { + if (a.types.stars !== b.types.stars) { return a.types.stars - b.types.stars; } + if (a.types.dynamics !== b.types.dynamics) { return a.types.dynamics - b.types.dynamics; } + if (a.types.statics !== b.types.statics) { return b.types.statics - a.types.statics; } + + return 0; + }); + } + + function recognizeChar(states, char) { + var nextStates = []; + + for (var i=0, l=states.length; i 0) { + currentResult.queryParams = activeQueryParams; + } + result.push(currentResult); + } + + return result; + } + + function addSegment(currentState, segment) { + segment.eachChar(function(char) { + var state; + + currentState = currentState.put(char); + }); + + return currentState; + } + + // The main interface + + var RouteRecognizer = function() { + this.rootState = new State(); + this.names = {}; + }; + + + RouteRecognizer.prototype = { + add: function(routes, options) { + var currentState = this.rootState, regex = "^", + types = { statics: 0, dynamics: 0, stars: 0 }, + handlers = [], allSegments = [], name; + + var isEmpty = true; + + for (var i=0, l=routes.length; i 1 && path.charAt(pathLen - 1) === "/") { + path = path.substr(0, pathLen - 1); + } + + for (i=0, l=path.length; i 0) { + var err = 'You supplied the params '; + err += missingParams.map(function(param) { + return '"' + param + "=" + queryParams[param] + '"'; + }).join(' and '); + + err += ' which are not valid for the "' + handlerName + '" handler or its parents'; + + throw new Error(err); + } + + return this.recognizer.generate(handlerName, params); + }, + + isActive: function(handlerName) { + var partitionedArgs = extractQueryParams(slice.call(arguments, 1)), + contexts = partitionedArgs[0], + queryParams = partitionedArgs[1], + activeQueryParams = {}, + effectiveQueryParams = {}; + + var targetHandlerInfos = this.targetHandlerInfos, + found = false, names, object, handlerInfo, handlerObj; + + if (!targetHandlerInfos) { return false; } + + var recogHandlers = this.recognizer.handlersFor(targetHandlerInfos[targetHandlerInfos.length - 1].name); + for (var i=targetHandlerInfos.length-1; i>=0; i--) { + handlerInfo = targetHandlerInfos[i]; + if (handlerInfo.name === handlerName) { found = true; } + + if (found) { + var recogHandler = recogHandlers[i]; + + merge(activeQueryParams, handlerInfo.queryParams); + if (queryParams !== false) { + merge(effectiveQueryParams, handlerInfo.queryParams); + mergeSomeKeys(effectiveQueryParams, queryParams, recogHandler.queryParams); + } + + if (handlerInfo.isDynamic && contexts.length > 0) { + object = contexts.pop(); + + if (isParam(object)) { + var name = recogHandler.names[0]; + if ("" + object !== this.currentParams[name]) { return false; } + } else if (handlerInfo.context !== object) { + return false; + } + } + } + } + + + return contexts.length === 0 && found && queryParamsEqual(activeQueryParams, effectiveQueryParams); + }, + + trigger: function(name) { + var args = slice.call(arguments); + trigger(this, this.currentHandlerInfos, false, args); + }, + + /** + Hook point for logging transition status updates. + + @param {String} message The message to log. + */ + log: null + }; + + /** + @private + + Used internally for both URL and named transition to determine + a shared pivot parent route and other data necessary to perform + a transition. + */ + function getMatchPoint(router, handlers, objects, inputParams, queryParams) { + + var matchPoint = handlers.length, + providedModels = {}, i, + currentHandlerInfos = router.currentHandlerInfos || [], + params = {}, + oldParams = router.currentParams || {}, + activeTransition = router.activeTransition, + handlerParams = {}, + obj; + + objects = slice.call(objects); + merge(params, inputParams); + + for (i = handlers.length - 1; i >= 0; i--) { + var handlerObj = handlers[i], + handlerName = handlerObj.handler, + oldHandlerInfo = currentHandlerInfos[i], + hasChanged = false; + + // Check if handler names have changed. + if (!oldHandlerInfo || oldHandlerInfo.name !== handlerObj.handler) { hasChanged = true; } + + if (handlerObj.isDynamic) { + // URL transition. + + if (obj = getMatchPointObject(objects, handlerName, activeTransition, true, params)) { + hasChanged = true; + providedModels[handlerName] = obj; + } else { + handlerParams[handlerName] = {}; + for (var prop in handlerObj.params) { + if (!handlerObj.params.hasOwnProperty(prop)) { continue; } + var newParam = handlerObj.params[prop]; + if (oldParams[prop] !== newParam) { hasChanged = true; } + handlerParams[handlerName][prop] = params[prop] = newParam; + } + } + } else if (handlerObj.hasOwnProperty('names')) { + // Named transition. + + if (objects.length) { hasChanged = true; } + + if (obj = getMatchPointObject(objects, handlerName, activeTransition, handlerObj.names[0], params)) { + providedModels[handlerName] = obj; + } else { + var names = handlerObj.names; + handlerParams[handlerName] = {}; + for (var j = 0, len = names.length; j < len; ++j) { + var name = names[j]; + handlerParams[handlerName][name] = params[name] = params[name] || oldParams[name]; + } + } + } + + // If there is an old handler, see if query params are the same. If there isn't an old handler, + // hasChanged will already be true here + if(oldHandlerInfo && !queryParamsEqual(oldHandlerInfo.queryParams, handlerObj.queryParams)) { + hasChanged = true; + } + + if (hasChanged) { matchPoint = i; } + } + + if (objects.length > 0) { + throw new Error("More context objects were passed than there are dynamic segments for the route: " + handlers[handlers.length - 1].handler); + } + + var pivotHandlerInfo = currentHandlerInfos[matchPoint - 1], + pivotHandler = pivotHandlerInfo && pivotHandlerInfo.handler; + + return { matchPoint: matchPoint, providedModels: providedModels, params: params, handlerParams: handlerParams, pivotHandler: pivotHandler }; + } + + function getMatchPointObject(objects, handlerName, activeTransition, paramName, params) { + + if (objects.length && paramName) { + + var object = objects.pop(); + + // If provided object is string or number, treat as param. + if (isParam(object)) { + params[paramName] = object.toString(); + } else { + return object; + } + } else if (activeTransition) { + // Use model from previous transition attempt, preferably the resolved one. + return activeTransition.resolvedModels[handlerName] || + (paramName && activeTransition.providedModels[handlerName]); + } + } + + function isParam(object) { + return (typeof object === "string" || object instanceof String || typeof object === "number" || object instanceof Number); + } + + + + /** + @private + + This method takes a handler name and returns a list of query params + that are valid to pass to the handler or its parents + + @param {Router} router + @param {String} handlerName + @return {Array[String]} a list of query parameters + */ + function queryParamsForHandler(router, handlerName) { + var handlers = router.recognizer.handlersFor(handlerName), + queryParams = []; + + for (var i = 0; i < handlers.length; i++) { + queryParams.push.apply(queryParams, handlers[i].queryParams || []); + } + + return queryParams; + } + /** + @private + + This method takes a handler name and a list of contexts and returns + a serialized parameter hash suitable to pass to `recognizer.generate()`. + + @param {Router} router + @param {String} handlerName + @param {Array[Object]} objects + @return {Object} a serialized parameter hash + */ + function paramsForHandler(router, handlerName, objects, queryParams) { + + var handlers = router.recognizer.handlersFor(handlerName), + params = {}, + handlerInfos = generateHandlerInfosWithQueryParams(router, handlers, queryParams), + matchPoint = getMatchPoint(router, handlerInfos, objects).matchPoint, + mergedQueryParams = {}, + object, handlerObj, handler, names, i; + + params.queryParams = {}; + + for (i=0; i= matchPoint) { + object = objects.shift(); + // Otherwise use existing context + } else { + object = handler.context; + } + + // Serialize to generate params + merge(params, serialize(handler, object, names)); + } + if (queryParams !== false) { + mergeSomeKeys(params.queryParams, router.currentQueryParams, handlerObj.queryParams); + mergeSomeKeys(params.queryParams, queryParams, handlerObj.queryParams); + } + } + + if (queryParamsEqual(params.queryParams, {})) { delete params.queryParams; } + return params; + } + + function merge(hash, other) { + for (var prop in other) { + if (other.hasOwnProperty(prop)) { hash[prop] = other[prop]; } + } + } + + function mergeSomeKeys(hash, other, keys) { + if (!other || !keys) { return; } + for(var i = 0; i < keys.length; i++) { + var key = keys[i], value; + if(other.hasOwnProperty(key)) { + value = other[key]; + if(value === null || value === false || typeof value === "undefined") { + delete hash[key]; + } else { + hash[key] = other[key]; + } + } + } + } + + /** + @private + */ + + function generateHandlerInfosWithQueryParams(router, handlers, queryParams) { + var handlerInfos = []; + + for (var i = 0; i < handlers.length; i++) { + var handler = handlers[i], + handlerInfo = { handler: handler.handler, names: handler.names, context: handler.context, isDynamic: handler.isDynamic }, + activeQueryParams = {}; + + if (queryParams !== false) { + mergeSomeKeys(activeQueryParams, router.currentQueryParams, handler.queryParams); + mergeSomeKeys(activeQueryParams, queryParams, handler.queryParams); + } + + if (handler.queryParams && handler.queryParams.length > 0) { + handlerInfo.queryParams = activeQueryParams; + } + + handlerInfos.push(handlerInfo); + } + + return handlerInfos; + } + + /** + @private + */ + function createQueryParamTransition(router, queryParams, isIntermediate) { + var currentHandlers = router.currentHandlerInfos, + currentHandler = currentHandlers[currentHandlers.length - 1], + name = currentHandler.name; + + log(router, "Attempting query param transition"); + + return createNamedTransition(router, [name, queryParams], isIntermediate); + } + + /** + @private + */ + function createNamedTransition(router, args, isIntermediate) { + var partitionedArgs = extractQueryParams(args), + pureArgs = partitionedArgs[0], + queryParams = partitionedArgs[1], + handlers = router.recognizer.handlersFor(pureArgs[0]), + handlerInfos = generateHandlerInfosWithQueryParams(router, handlers, queryParams); + + + log(router, "Attempting transition to " + pureArgs[0]); + + return performTransition(router, + handlerInfos, + slice.call(pureArgs, 1), + router.currentParams, + queryParams, + null, + isIntermediate); + } + + /** + @private + */ + function createURLTransition(router, url, isIntermediate) { + var results = router.recognizer.recognize(url), + currentHandlerInfos = router.currentHandlerInfos, + queryParams = {}, + i, len; + + log(router, "Attempting URL transition to " + url); + + if (results) { + // Make sure this route is actually accessible by URL. + for (i = 0, len = results.length; i < len; ++i) { + + if (router.getHandler(results[i].handler).inaccessibleByURL) { + results = null; + break; + } + } + } + + if (!results) { + return errorTransition(router, new Router.UnrecognizedURLError(url)); + } + + for(i = 0, len = results.length; i < len; i++) { + merge(queryParams, results[i].queryParams); + } + + return performTransition(router, results, [], {}, queryParams, null, isIntermediate); + } + + + /** + @private + + Takes an Array of `HandlerInfo`s, figures out which ones are + exiting, entering, or changing contexts, and calls the + proper handler hooks. + + For example, consider the following tree of handlers. Each handler is + followed by the URL segment it handles. + + ``` + |~index ("/") + | |~posts ("/posts") + | | |-showPost ("/:id") + | | |-newPost ("/new") + | | |-editPost ("/edit") + | |~about ("/about/:id") + ``` + + Consider the following transitions: + + 1. A URL transition to `/posts/1`. + 1. Triggers the `*model` callbacks on the + `index`, `posts`, and `showPost` handlers + 2. Triggers the `enter` callback on the same + 3. Triggers the `setup` callback on the same + 2. A direct transition to `newPost` + 1. Triggers the `exit` callback on `showPost` + 2. Triggers the `enter` callback on `newPost` + 3. Triggers the `setup` callback on `newPost` + 3. A direct transition to `about` with a specified + context object + 1. Triggers the `exit` callback on `newPost` + and `posts` + 2. Triggers the `serialize` callback on `about` + 3. Triggers the `enter` callback on `about` + 4. Triggers the `setup` callback on `about` + + @param {Transition} transition + @param {Array[HandlerInfo]} handlerInfos + */ + function setupContexts(transition, handlerInfos) { + var router = transition.router, + partition = partitionHandlers(router.currentHandlerInfos || [], handlerInfos); + + router.targetHandlerInfos = handlerInfos; + + eachHandler(partition.exited, function(handlerInfo) { + var handler = handlerInfo.handler; + delete handler.context; + if (handler.exit) { handler.exit(); } + }); + + var currentHandlerInfos = partition.unchanged.slice(); + router.currentHandlerInfos = currentHandlerInfos; + + eachHandler(partition.updatedContext, function(handlerInfo) { + handlerEnteredOrUpdated(transition, currentHandlerInfos, handlerInfo, false); + }); + + eachHandler(partition.entered, function(handlerInfo) { + handlerEnteredOrUpdated(transition, currentHandlerInfos, handlerInfo, true); + }); + } + + /** + @private + + Helper method used by setupContexts. Handles errors or redirects + that may happen in enter/setup. + */ + function handlerEnteredOrUpdated(transition, currentHandlerInfos, handlerInfo, enter) { + var handler = handlerInfo.handler, + context = handlerInfo.context; + + try { + if (enter && handler.enter) { handler.enter(); } + checkAbort(transition); + + setContext(handler, context); + setQueryParams(handler, handlerInfo.queryParams); + + if (handler.setup) { handler.setup(context, handlerInfo.queryParams); } + checkAbort(transition); + } catch(e) { + if (!(e instanceof Router.TransitionAborted)) { + // Trigger the `error` event starting from this failed handler. + transition.trigger(true, 'error', e, transition, handler); + } + + // Propagate the error so that the transition promise will reject. + throw e; + } + + currentHandlerInfos.push(handlerInfo); + } + + + /** + @private + + Iterates over an array of `HandlerInfo`s, passing the handler + and context into the callback. + + @param {Array[HandlerInfo]} handlerInfos + @param {Function(Object, Object)} callback + */ + function eachHandler(handlerInfos, callback) { + for (var i=0, l=handlerInfos.length; i=0; i--) { + var handlerInfo = handlerInfos[i], + handler = handlerInfo.handler; + + if (handler.events && handler.events[name]) { + if (handler.events[name].apply(handler, args) === true) { + eventWasHandled = true; + } else { + return; + } + } + } + + if (!eventWasHandled && !ignoreFailure) { + throw new Error("Nothing handled the event '" + name + "'."); + } + } + + function setContext(handler, context) { + handler.context = context; + if (handler.contextDidChange) { handler.contextDidChange(); } + } + + function setQueryParams(handler, queryParams) { + handler.queryParams = queryParams; + if (handler.queryParamsDidChange) { handler.queryParamsDidChange(); } + } + + + /** + @private + + Extracts query params from the end of an array + **/ + + function extractQueryParams(array) { + var len = (array && array.length), head, queryParams; + + if(len && len > 0 && array[len - 1] && array[len - 1].hasOwnProperty('queryParams')) { + queryParams = array[len - 1].queryParams; + head = slice.call(array, 0, len - 1); + return [head, queryParams]; + } else { + return [array, null]; + } + } + + function performIntermediateTransition(router, recogHandlers, matchPointResults) { + + var handlerInfos = generateHandlerInfos(router, recogHandlers); + for (var i = 0; i < handlerInfos.length; ++i) { + var handlerInfo = handlerInfos[i]; + handlerInfo.context = matchPointResults.providedModels[handlerInfo.name]; + } + + var stubbedTransition = { + router: router, + isAborted: false + }; + + setupContexts(stubbedTransition, handlerInfos); + } + + /** + @private + + Creates, begins, and returns a Transition. + */ + function performTransition(router, recogHandlers, providedModelsArray, params, queryParams, data, isIntermediate) { + + var matchPointResults = getMatchPoint(router, recogHandlers, providedModelsArray, params, queryParams), + targetName = recogHandlers[recogHandlers.length - 1].handler, + wasTransitioning = false, + currentHandlerInfos = router.currentHandlerInfos; + + if (isIntermediate) { + return performIntermediateTransition(router, recogHandlers, matchPointResults); + } + + // Check if there's already a transition underway. + if (router.activeTransition) { + if (transitionsIdentical(router.activeTransition, targetName, providedModelsArray, queryParams)) { + return router.activeTransition; + } + router.activeTransition.abort(); + wasTransitioning = true; + } + + var deferred = RSVP.defer(), + transition = new Transition(router, deferred.promise); + + transition.targetName = targetName; + transition.providedModels = matchPointResults.providedModels; + transition.providedModelsArray = providedModelsArray; + transition.params = matchPointResults.params; + transition.data = data || {}; + transition.queryParams = queryParams; + transition.pivotHandler = matchPointResults.pivotHandler; + router.activeTransition = transition; + + var handlerInfos = generateHandlerInfos(router, recogHandlers); + transition.handlerInfos = handlerInfos; + + // Fire 'willTransition' event on current handlers, but don't fire it + // if a transition was already underway. + if (!wasTransitioning) { + trigger(router, currentHandlerInfos, true, ['willTransition', transition]); + } + + log(router, transition.sequence, "Beginning validation for transition to " + transition.targetName); + validateEntry(transition, matchPointResults.matchPoint, matchPointResults.handlerParams) + .then(transitionSuccess, transitionFailure); + + return transition; + + function transitionSuccess() { + checkAbort(transition); + + try { + finalizeTransition(transition, handlerInfos); + + // currentHandlerInfos was updated in finalizeTransition + trigger(router, router.currentHandlerInfos, true, ['didTransition']); + + if (router.didTransition) { + router.didTransition(handlerInfos); + } + + log(router, transition.sequence, "TRANSITION COMPLETE."); + + // Resolve with the final handler. + transition.isActive = false; + deferred.resolve(handlerInfos[handlerInfos.length - 1].handler); + } catch(e) { + deferred.reject(e); + } + + // Don't nullify if another transition is underway (meaning + // there was a transition initiated with enter/setup). + if (!transition.isAborted) { + router.activeTransition = null; + } + } + + function transitionFailure(reason) { + deferred.reject(reason); + } + } + + /** + @private + + Accepts handlers in Recognizer format, either returned from + recognize() or handlersFor(), and returns unified + `HandlerInfo`s. + */ + function generateHandlerInfos(router, recogHandlers) { + var handlerInfos = []; + for (var i = 0, len = recogHandlers.length; i < len; ++i) { + var handlerObj = recogHandlers[i], + isDynamic = handlerObj.isDynamic || (handlerObj.names && handlerObj.names.length); + + var handlerInfo = { + isDynamic: !!isDynamic, + name: handlerObj.handler, + handler: router.getHandler(handlerObj.handler) + }; + if(handlerObj.queryParams) { + handlerInfo.queryParams = handlerObj.queryParams; + } + handlerInfos.push(handlerInfo); + } + return handlerInfos; + } + + /** + @private + */ + function transitionsIdentical(oldTransition, targetName, providedModelsArray, queryParams) { + + if (oldTransition.targetName !== targetName) { return false; } + + var oldModels = oldTransition.providedModelsArray; + if (oldModels.length !== providedModelsArray.length) { return false; } + + for (var i = 0, len = oldModels.length; i < len; ++i) { + if (oldModels[i] !== providedModelsArray[i]) { return false; } + } + + if(!queryParamsEqual(oldTransition.queryParams, queryParams)) { + return false; + } + + return true; + } + + /** + @private + + Updates the URL (if necessary) and calls `setupContexts` + to update the router's array of `currentHandlerInfos`. + */ + function finalizeTransition(transition, handlerInfos) { + + log(transition.router, transition.sequence, "Validation succeeded, finalizing transition;"); + + var router = transition.router, + seq = transition.sequence, + handlerName = handlerInfos[handlerInfos.length - 1].name, + urlMethod = transition.urlMethod, + i; + + // Collect params for URL. + var objects = [], providedModels = transition.providedModelsArray.slice(); + for (i = handlerInfos.length - 1; i>=0; --i) { + var handlerInfo = handlerInfos[i]; + if (handlerInfo.isDynamic) { + var providedModel = providedModels.pop(); + objects.unshift(isParam(providedModel) ? providedModel.toString() : handlerInfo.context); + } + + if (handlerInfo.handler.inaccessibleByURL) { + urlMethod = null; + } + } + + var newQueryParams = {}; + for (i = handlerInfos.length - 1; i>=0; --i) { + merge(newQueryParams, handlerInfos[i].queryParams); + } + router.currentQueryParams = newQueryParams; + + + var params = paramsForHandler(router, handlerName, objects, transition.queryParams); + + router.currentParams = params; + + if (urlMethod) { + var url = router.recognizer.generate(handlerName, params); + + if (urlMethod === 'replace') { + router.replaceURL(url); + } else { + // Assume everything else is just a URL update for now. + router.updateURL(url); + } + } + + setupContexts(transition, handlerInfos); + } + + /** + @private + + Internal function used to construct the chain of promises used + to validate a transition. Wraps calls to `beforeModel`, `model`, + and `afterModel` in promises, and checks for redirects/aborts + between each. + */ + function validateEntry(transition, matchPoint, handlerParams) { + + var handlerInfos = transition.handlerInfos, + index = transition.resolveIndex; + + if (index === handlerInfos.length) { + // No more contexts to resolve. + return RSVP.resolve(transition.resolvedModels); + } + + var router = transition.router, + handlerInfo = handlerInfos[index], + handler = handlerInfo.handler, + handlerName = handlerInfo.name, + seq = transition.sequence; + + if (index < matchPoint) { + log(router, seq, handlerName + ": using context from already-active handler"); + + // We're before the match point, so don't run any hooks, + // just use the already resolved context from the handler. + transition.resolvedModels[handlerInfo.name] = + transition.providedModels[handlerInfo.name] || + handlerInfo.handler.context; + return proceed(); + } + + transition.trigger(true, 'willResolveModel', transition, handler); + + return RSVP.resolve().then(handleAbort) + .then(beforeModel) + .then(handleAbort) + .then(model) + .then(handleAbort) + .then(afterModel) + .then(handleAbort) + .then(null, handleError) + .then(proceed); + + function handleAbort(result) { + if (transition.isAborted) { + log(transition.router, transition.sequence, "detected abort."); + return RSVP.reject(new Router.TransitionAborted()); + } + + return result; + } + + function handleError(reason) { + if (reason instanceof Router.TransitionAborted || transition.isAborted) { + // if the transition was aborted and *no additional* error was thrown, + // reject with the Router.TransitionAborted instance + return RSVP.reject(reason); + } + + // otherwise, we're here because of a different error + transition.abort(); + + log(router, seq, handlerName + ": handling error: " + reason); + + // An error was thrown / promise rejected, so fire an + // `error` event from this handler info up to root. + transition.trigger(true, 'error', reason, transition, handlerInfo.handler); + + // Propagate the original error. + return RSVP.reject(reason); + } + + function beforeModel() { + + log(router, seq, handlerName + ": calling beforeModel hook"); + + var args; + + if (handlerInfo.queryParams) { + args = [handlerInfo.queryParams, transition]; + } else { + args = [transition]; + } + + var p = handler.beforeModel && handler.beforeModel.apply(handler, args); + return (p instanceof Transition) ? null : p; + } + + function model() { + log(router, seq, handlerName + ": resolving model"); + var p = getModel(handlerInfo, transition, handlerParams[handlerName], index >= matchPoint); + return (p instanceof Transition) ? null : p; + } + + function afterModel(context) { + + log(router, seq, handlerName + ": calling afterModel hook"); + + // Pass the context and resolved parent contexts to afterModel, but we don't + // want to use the value returned from `afterModel` in any way, but rather + // always resolve with the original `context` object. + + transition.resolvedModels[handlerInfo.name] = context; + + var args; + + if (handlerInfo.queryParams) { + args = [context, handlerInfo.queryParams, transition]; + } else { + args = [context, transition]; + } + + var p = handler.afterModel && handler.afterModel.apply(handler, args); + return (p instanceof Transition) ? null : p; + } + + function proceed() { + log(router, seq, handlerName + ": validation succeeded, proceeding"); + + handlerInfo.context = transition.resolvedModels[handlerInfo.name]; + transition.resolveIndex++; + return validateEntry(transition, matchPoint, handlerParams); + } + } + + /** + @private + + Throws a TransitionAborted if the provided transition has been aborted. + */ + function checkAbort(transition) { + if (transition.isAborted) { + log(transition.router, transition.sequence, "detected abort."); + throw new Router.TransitionAborted(); + } + } + + /** + @private + + Encapsulates the logic for whether to call `model` on a route, + or use one of the models provided to `transitionTo`. + */ + function getModel(handlerInfo, transition, handlerParams, needsUpdate) { + var handler = handlerInfo.handler, + handlerName = handlerInfo.name, args; + + if (!needsUpdate && handler.hasOwnProperty('context')) { + return handler.context; + } + + if (transition.providedModels.hasOwnProperty(handlerName)) { + var providedModel = transition.providedModels[handlerName]; + return typeof providedModel === 'function' ? providedModel() : providedModel; + } + + if (handlerInfo.queryParams) { + args = [handlerParams || {}, handlerInfo.queryParams, transition]; + } else { + args = [handlerParams || {}, transition, handlerInfo.queryParams]; + } + + return handler.model && handler.model.apply(handler, args); + } + + /** + @private + */ + function log(router, sequence, msg) { + + if (!router.log) { return; } + + if (arguments.length === 3) { + router.log("Transition #" + sequence + ": " + msg); + } else { + msg = sequence; + router.log(msg); + } + } + + /** + @private + + Begins and returns a Transition based on the provided + arguments. Accepts arguments in the form of both URL + transitions and named transitions. + + @param {Router} router + @param {Array[Object]} args arguments passed to transitionTo, + replaceWith, or handleURL + */ + function doTransition(router, args, isIntermediate) { + // Normalize blank transitions to root URL transitions. + var name = args[0] || '/'; + + if(args.length === 1 && args[0].hasOwnProperty('queryParams')) { + return createQueryParamTransition(router, args[0], isIntermediate); + } else if (name.charAt(0) === '/') { + return createURLTransition(router, name, isIntermediate); + } else { + return createNamedTransition(router, slice.call(args), isIntermediate); + } + } + + /** + @private + + Serializes a handler using its custom `serialize` method or + by a default that looks up the expected property name from + the dynamic segment. + + @param {Object} handler a router handler + @param {Object} model the model to be serialized for this handler + @param {Array[Object]} names the names array attached to an + handler object returned from router.recognizer.handlersFor() + */ + function serialize(handler, model, names) { + + var object = {}; + if (isParam(model)) { + object[names[0]] = model; + return object; + } + + // Use custom serialize if it exists. + if (handler.serialize) { + return handler.serialize(model, names); + } + + if (names.length !== 1) { return; } + + var name = names[0]; + + if (/_id$/.test(name)) { + object[name] = model.id; + } else { + object[name] = model; + } + return object; + } + }); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-routing +*/ + +function DSL(name) { + this.parent = name; + this.matches = []; +} + +DSL.prototype = { + resource: function(name, options, callback) { + if (arguments.length === 2 && typeof options === 'function') { + callback = options; + options = {}; + } + + if (arguments.length === 1) { + options = {}; + } + + if (typeof options.path !== 'string') { + options.path = "/" + name; + } + + if (callback) { + var dsl = new DSL(name); + route(dsl, 'loading'); + route(dsl, 'error', { path: "/_unused_dummy_error_path_route_" + name + "/:error" }); + callback.call(dsl); + this.push(options.path, name, dsl.generate(), options.queryParams); + } else { + this.push(options.path, name, null, options.queryParams); + } + + }, + + push: function(url, name, callback, queryParams) { + var parts = name.split('.'); + if (url === "" || url === "/" || parts[parts.length-1] === "index") { this.explicitIndex = true; } + + this.matches.push([url, name, callback, queryParams]); + }, + + route: function(name, options) { + route(this, name, options); + }, + + generate: function() { + var dslMatches = this.matches; + + if (!this.explicitIndex) { + this.route("index", { path: "/" }); + } + + return function(match) { + for (var i=0, l=dslMatches.length; i " + fullName, { fullName: fullName }); + } + + return instance; +}; + +})(); + + + +(function() { +/** +@module ember +@submodule ember-routing +*/ + +var Router = requireModule("router")['default']; +var get = Ember.get, set = Ember.set; +var defineProperty = Ember.defineProperty; + +var DefaultView = Ember._MetamorphView; +/** + The `Ember.Router` class manages the application state and URLs. Refer to + the [routing guide](http://emberjs.com/guides/routing/) for documentation. + + @class Router + @namespace Ember + @extends Ember.Object +*/ +Ember.Router = Ember.Object.extend(Ember.Evented, { + location: 'hash', + + init: function() { + this.router = this.constructor.router || this.constructor.map(Ember.K); + this._activeViews = {}; + this._setupLocation(); + }, + + url: Ember.computed(function() { + return get(this, 'location').getURL(); + }), + + startRouting: function() { + this.router = this.router || this.constructor.map(Ember.K); + + var router = this.router, + location = get(this, 'location'), + container = this.container, + self = this; + + this._setupRouter(router, location); + + container.register('view:default', DefaultView); + container.register('view:toplevel', Ember.View.extend()); + + location.onUpdateURL(function(url) { + self.handleURL(url); + }); + + this.handleURL(location.getURL()); + }, + + didTransition: function(infos) { + updatePaths(this); + + + this._cancelLoadingEvent(); + + this.notifyPropertyChange('url'); + + + // Put this in the runloop so url will be accurate. Seems + // less surprising than didTransition being out of sync. + Ember.run.once(this, this.trigger, 'didTransition'); + + + if (get(this, 'namespace').LOG_TRANSITIONS) { + Ember.Logger.log("Transitioned into '" + Ember.Router._routePath(infos) + "'"); + } + }, + + handleURL: function(url) { + return this._doTransition('handleURL', [url]); + }, + + transitionTo: function() { + return this._doTransition('transitionTo', arguments); + }, + + intermediateTransitionTo: function() { + this.router.intermediateTransitionTo.apply(this.router, arguments); + + updatePaths(this); + + var infos = this.router.currentHandlerInfos; + if (get(this, 'namespace').LOG_TRANSITIONS) { + Ember.Logger.log("Intermediate-transitioned into '" + Ember.Router._routePath(infos) + "'"); + } + }, + + replaceWith: function() { + return this._doTransition('replaceWith', arguments); + }, + + generate: function() { + var url = this.router.generate.apply(this.router, arguments); + return this.location.formatURL(url); + }, + + isActive: function(routeName) { + var router = this.router; + return router.isActive.apply(router, arguments); + }, + + send: function(name, context) { + this.router.trigger.apply(this.router, arguments); + }, + + hasRoute: function(route) { + return this.router.hasRoute(route); + }, + + /** + @private + + Resets the state of the router by clearing the current route + handlers and deactivating them. + + @method reset + */ + reset: function() { + this.router.reset(); + }, + + willDestroy: function(){ + var location = get(this, 'location'); + location.destroy(); + + this._super.apply(this, arguments); + }, + + _lookupActiveView: function(templateName) { + var active = this._activeViews[templateName]; + return active && active[0]; + }, + + _connectActiveView: function(templateName, view) { + var existing = this._activeViews[templateName]; + + if (existing) { + existing[0].off('willDestroyElement', this, existing[1]); + } + + var disconnect = function() { + delete this._activeViews[templateName]; + }; + + this._activeViews[templateName] = [view, disconnect]; + view.one('willDestroyElement', this, disconnect); + }, + + _setupLocation: function() { + var location = get(this, 'location'), + rootURL = get(this, 'rootURL'), + options = {}; + + if (typeof rootURL === 'string') { + options.rootURL = rootURL; + } + + if ('string' === typeof location) { + options.implementation = location; + location = set(this, 'location', Ember.Location.create(options)); + } + }, + + _getHandlerFunction: function() { + var seen = {}, container = this.container, + DefaultRoute = container.lookupFactory('route:basic'), + self = this; + + return function(name) { + var routeName = 'route:' + name, + handler = container.lookup(routeName); + + if (seen[name]) { return handler; } + + seen[name] = true; + + if (!handler) { + + + container.register(routeName, DefaultRoute.extend()); + handler = container.lookup(routeName); + + if (get(self, 'namespace.LOG_ACTIVE_GENERATION')) { + Ember.Logger.info("generated -> " + routeName, { fullName: routeName }); + } + } + + handler.routeName = name; + return handler; + }; + }, + + _setupRouter: function(router, location) { + var lastURL, emberRouter = this; + + router.getHandler = this._getHandlerFunction(); + + var doUpdateURL = function() { + location.setURL(lastURL); + }; + + router.updateURL = function(path) { + lastURL = path; + Ember.run.once(doUpdateURL); + }; + + if (location.replaceURL) { + var doReplaceURL = function() { + location.replaceURL(lastURL); + }; + + router.replaceURL = function(path) { + lastURL = path; + Ember.run.once(doReplaceURL); + }; + } + + router.didTransition = function(infos) { + emberRouter.didTransition(infos); + }; + }, + + _doTransition: function(method, args) { + // Normalize blank route to root URL. + args = [].slice.call(args); + args[0] = args[0] || '/'; + + var passedName = args[0], name, self = this, + isQueryParamsOnly = false; + + + if (!isQueryParamsOnly && passedName.charAt(0) === '/') { + name = passedName; + } else if (!isQueryParamsOnly) { + if (!this.router.hasRoute(passedName)) { + name = args[0] = passedName + '.index'; + } else { + name = passedName; + } + + Ember.assert("The route " + passedName + " was not found", this.router.hasRoute(name)); + } + + var transitionPromise = this.router[method].apply(this.router, args); + + // Don't schedule loading state entry if user has already aborted the transition. + + + transitionPromise.then(null, function(error) { + if (error.name === "UnrecognizedURLError") { + Ember.assert("The URL '" + error.message + "' did not match any routes in your application"); + } + }); + + // We want to return the configurable promise object + // so that callers of this function can use `.method()` on it, + // which obviously doesn't exist for normal RSVP promises. + return transitionPromise; + }, + + _scheduleLoadingEvent: function(transition, originRoute) { + this._cancelLoadingEvent(); + + this._loadingStateTimer = Ember.run.scheduleOnce('routerTransitions', this, '_fireLoadingEvent', transition, originRoute); + + }, + + _fireLoadingEvent: function(transition, originRoute) { + + if (!this.router.activeTransition) { + // Don't fire an event if we've since moved on from + // the transition that put us in a loading state. + return; + } + + transition.trigger(true, 'loading', transition, originRoute); + }, + + _cancelLoadingEvent: function () { + if (this._loadingStateTimer) { + Ember.run.cancel(this._loadingStateTimer); + } + this._loadingStateTimer = null; + } +}); + +/** + @private + + Helper function for iterating root-ward, starting + from (but not including) the provided `originRoute`. + + Returns true if the last callback fired requested + to bubble upward. + */ +function forEachRouteAbove(originRoute, transition, callback) { + var handlerInfos = transition.handlerInfos, + originRouteFound = false; + + for (var i = handlerInfos.length - 1; i >= 0; --i) { + var handlerInfo = handlerInfos[i], + route = handlerInfo.handler; + + if (!originRouteFound) { + if (originRoute === route) { + originRouteFound = true; + } + continue; + } + + if (callback(route, handlerInfos[i + 1].handler) !== true) { + return false; + } + } + return true; +} + +// These get invoked when an action bubbles above ApplicationRoute +// and are not meant to be overridable. +var defaultActionHandlers = { + + willResolveModel: function(transition, originRoute) { + originRoute.router._scheduleLoadingEvent(transition, originRoute); + }, + + error: function(error, transition, originRoute) { + + + // Attempt to find an appropriate error substate to enter. + var router = originRoute.router; + + var tryTopLevel = forEachRouteAbove(originRoute, transition, function(route, childRoute) { + var childErrorRouteName = findChildRouteName(route, childRoute, 'error'); + if (childErrorRouteName) { + router.intermediateTransitionTo(childErrorRouteName, error); + return; + } + return true; + }); + + if (tryTopLevel) { + // Check for top-level error state to enter. + if (routeHasBeenDefined(originRoute.router, 'application_error')) { + router.intermediateTransitionTo('application_error', error); + return; + } + } else { + // Don't fire an assertion if we found an error substate. + return; + } + + + Ember.Logger.assert(false, 'Error while loading route: ' + Ember.inspect(error)); + }, + + loading: function(transition, originRoute) { + + + // Attempt to find an appropriate loading substate to enter. + var router = originRoute.router; + + var tryTopLevel = forEachRouteAbove(originRoute, transition, function(route, childRoute) { + var childLoadingRouteName = findChildRouteName(route, childRoute, 'loading'); + + if (childLoadingRouteName) { + router.intermediateTransitionTo(childLoadingRouteName); + return; + } + + // Don't bubble above pivot route. + if (transition.pivotHandler !== route) { + return true; + } + }); + + if (tryTopLevel) { + // Check for top-level loading state to enter. + if (routeHasBeenDefined(originRoute.router, 'application_loading')) { + router.intermediateTransitionTo('application_loading'); + return; + } + } + + } +}; + +function findChildRouteName(parentRoute, originatingChildRoute, name) { + var router = parentRoute.router, + childName, + targetChildRouteName = originatingChildRoute.routeName.split('.').pop(), + namespace = parentRoute.routeName === 'application' ? '' : parentRoute.routeName + '.'; + + childName = namespace + name; + if (routeHasBeenDefined(router, childName)) { + return childName; + } +} + +function routeHasBeenDefined(router, name) { + var container = router.container; + return router.hasRoute(name) && + (container.has('template:' + name) || container.has('route:' + name)); +} + +function triggerEvent(handlerInfos, ignoreFailure, args) { + var name = args.shift(); + + if (!handlerInfos) { + if (ignoreFailure) { return; } + throw new Ember.Error("Can't trigger action '" + name + "' because your app hasn't finished transitioning into its first route. To trigger an action on destination routes during a transition, you can call `.send()` on the `Transition` object passed to the `model/beforeModel/afterModel` hooks."); + } + + var eventWasHandled = false; + + for (var i = handlerInfos.length - 1; i >= 0; i--) { + var handlerInfo = handlerInfos[i], + handler = handlerInfo.handler; + + if (handler._actions && handler._actions[name]) { + if (handler._actions[name].apply(handler, args) === true) { + eventWasHandled = true; + } else { + return; + } + } + } + + if (defaultActionHandlers[name]) { + defaultActionHandlers[name].apply(null, args); + return; + } + + if (!eventWasHandled && !ignoreFailure) { + throw new Ember.Error("Nothing handled the action '" + name + "'."); + } +} + +function updatePaths(router) { + var appController = router.container.lookup('controller:application'); + + if (!appController) { + // appController might not exist when top-level loading/error + // substates have been entered since ApplicationRoute hasn't + // actually been entered at that point. + return; + } + + var infos = router.router.currentHandlerInfos, + path = Ember.Router._routePath(infos); + + if (!('currentPath' in appController)) { + defineProperty(appController, 'currentPath'); + } + + set(appController, 'currentPath', path); + + if (!('currentRouteName' in appController)) { + defineProperty(appController, 'currentRouteName'); + } + + set(appController, 'currentRouteName', infos[infos.length - 1].name); +} + +function scheduleLegacyLoadingRouteEntry(router) { + cancelLegacyLoadingRouteEntry(router); + if (router.router.activeTransition) { + router._legacyLoadingStateTimer = Ember.run.scheduleOnce('routerTransitions', null, enterLegacyLoadingRoute, router); + } +} + +function enterLegacyLoadingRoute(router) { + var loadingRoute = router.router.getHandler('loading'); + if (loadingRoute && !loadingRoute._loadingStateActive) { + if (loadingRoute.enter) { loadingRoute.enter(); } + if (loadingRoute.setup) { loadingRoute.setup(); } + loadingRoute._loadingStateActive = true; + } +} + +function cancelLegacyLoadingRouteEntry(router) { + if (router._legacyLoadingStateTimer) { + Ember.run.cancel(router._legacyLoadingStateTimer); + } + router._legacyLoadingStateTimer = null; +} + +function exitLegacyLoadingRoute(router) { + + cancelLegacyLoadingRouteEntry(router); + + var loadingRoute = router.router.getHandler('loading'); + + if (loadingRoute && loadingRoute._loadingStateActive) { + if (loadingRoute.exit) { loadingRoute.exit(); } + loadingRoute._loadingStateActive = false; + } +} + +Ember.Router.reopenClass({ + router: null, + map: function(callback) { + var router = this.router; + if (!router) { + router = new Router(); + router.callbacks = []; + router.triggerEvent = triggerEvent; + this.reopenClass({ router: router }); + } + + if (get(this, 'namespace.LOG_TRANSITIONS_INTERNAL')) { + router.log = Ember.Logger.debug; + } + + var dsl = Ember.RouterDSL.map(function() { + this.resource('application', { path: "/" }, function() { + for (var i=0; i < router.callbacks.length; i++) { + router.callbacks[i].call(this); + } + callback.call(this); + }); + }); + + router.callbacks.push(callback); + router.map(dsl.generate()); + return router; + }, + + _routePath: function(handlerInfos) { + var path = []; + + for (var i=1, l=handlerInfos.length; i 0 ? !Ember.isNone(arguments[0]) : true); + + var namePassed = !!name; + + if (typeof name === 'object' && !options) { + options = name; + name = this.routeName; + } + + options = options || {}; + + var templateName; + + if (name) { + name = name.replace(/\//g, '.'); + templateName = name; + } else { + name = this.routeName; + templateName = this.templateName || name; + } + + var viewName = options.view || this.viewName || name; + + var container = this.container, + view = container.lookup('view:' + viewName), + template = view ? view.get('template') : null; + + if (!template) { + template = container.lookup('template:' + templateName); + } + + if (!view && !template) { + Ember.assert("Could not find \"" + name + "\" template or view.", !namePassed); + if (get(this.router, 'namespace.LOG_VIEW_LOOKUPS')) { + Ember.Logger.info("Could not find \"" + name + "\" template or view. Nothing will be rendered", { fullName: 'template:' + name }); + } + return; + } + + options = normalizeOptions(this, name, template, options); + view = setupView(view, container, options); + + if (options.outlet === 'main') { this.lastRenderedTemplate = name; } + + appendView(this, view, options); + }, + + /** + Disconnects a view that has been rendered into an outlet. + + You may pass any or all of the following options to `disconnectOutlet`: + + * `outlet`: the name of the outlet to clear (default: 'main') + * `parentView`: the name of the view containing the outlet to clear + (default: the view rendered by the parent route) + + Example: + + ```js + App.ApplicationRoute = App.Route.extend({ + actions: { + showModal: function(evt) { + this.render(evt.modalName, { + outlet: 'modal', + into: 'application' + }); + }, + hideModal: function(evt) { + this.disconnectOutlet({ + outlet: 'modal', + parentView: 'application' + }); + } + } + }); + ``` + + @method disconnectOutlet + @param {Object} options the options + */ + disconnectOutlet: function(options) { + options = options || {}; + options.parentView = options.parentView ? options.parentView.replace(/\//g, '.') : parentTemplate(this); + options.outlet = options.outlet || 'main'; + + var parentView = this.router._lookupActiveView(options.parentView); + parentView.disconnectOutlet(options.outlet); + }, + + willDestroy: function() { + this.teardownViews(); + }, + + /** + @private + + @method teardownViews + */ + teardownViews: function() { + // Tear down the top level view + if (this.teardownTopLevelView) { this.teardownTopLevelView(); } + + // Tear down any outlets rendered with 'into' + var teardownOutletViews = this.teardownOutletViews || []; + a_forEach(teardownOutletViews, function(teardownOutletView) { + teardownOutletView(); + }); + + delete this.teardownTopLevelView; + delete this.teardownOutletViews; + delete this.lastRenderedTemplate; + } +}); + +function parentRoute(route) { + var handlerInfos = route.router.router.targetHandlerInfos; + + if (!handlerInfos) { return; } + + var parent, current; + + for (var i=0, l=handlerInfos.length; i + Great Hamster Photos + + ``` + + ### Supplying a tagName + By default `{{link-to}}` renders an `` element. This can + be overridden for a single use of `{{link-to}}` by supplying + a `tagName` option: + + ```handlebars + {{#link-to 'photoGallery' tagName="li"}} + Great Hamster Photos + {{/link-to}} + ``` + + ```html +
  • + Great Hamster Photos +
  • + ``` + + To override this option for your entire application, see + "Overriding Application-wide Defaults". + + ### Disabling the `link-to` helper + By default `{{link-to}}` is enabled. + any passed value to `disabled` helper property will disable the `link-to` helper. + + static use: the `disabled` option: + + ```handlebars + {{#link-to 'photoGallery' disabled=true}} + Great Hamster Photos + {{/link-to}} + ``` + + dynamic use: the `disabledWhen` option: + + ```handlebars + {{#link-to 'photoGallery' disabledWhen=controller.someProperty}} + Great Hamster Photos + {{/link-to}} + ``` + + any passed value to `disabled` will disable it except `undefined`. + to ensure that only `true` disable the `link-to` helper you can + override the global behaviour of `Ember.LinkView`. + + ```javascript + Ember.LinkView.reopen({ + disabled: Ember.computed(function(key, value) { + if (value !== undefined) { + this.set('_isDisabled', value === true); + } + return value === true ? get(this, 'disabledClass') : false; + }) + }); + ``` + + see "Overriding Application-wide Defaults" for more. + + ### Handling `href` + `{{link-to}}` will use your application's Router to + fill the element's `href` property with a url that + matches the path to the supplied `routeName` for your + routers's configured `Location` scheme, which defaults + to Ember.HashLocation. + + ### Handling current route + `{{link-to}}` will apply a CSS class name of 'active' + when the application's current route matches + the supplied routeName. For example, if the application's + current route is 'photoGallery.recent' the following + use of `{{link-to}}`: + + ```handlebars + {{#link-to 'photoGallery.recent'}} + Great Hamster Photos from the last week + {{/link-to}} + ``` + + will result in + + ```html +
    + Great Hamster Photos + + ``` + + The CSS class name used for active classes can be customized + for a single use of `{{link-to}}` by passing an `activeClass` + option: + + ```handlebars + {{#link-to 'photoGallery.recent' activeClass="current-url"}} + Great Hamster Photos from the last week + {{/link-to}} + ``` + + ```html + + Great Hamster Photos + + ``` + + To override this option for your entire application, see + "Overriding Application-wide Defaults". + + ### Supplying a model + An optional model argument can be used for routes whose + paths contain dynamic segments. This argument will become + the model context of the linked route: + + ```javascript + App.Router.map(function() { + this.resource("photoGallery", {path: "hamster-photos/:photo_id"}); + }); + ``` + + ```handlebars + {{#link-to 'photoGallery' aPhoto}} + {{aPhoto.title}} + {{/link-to}} + ``` + + ```html + + Tomster + + ``` + + ### Supplying multiple models + For deep-linking to route paths that contain multiple + dynamic segments, multiple model arguments can be used. + As the router transitions through the route path, each + supplied model argument will become the context for the + route with the dynamic segments: + + ```javascript + App.Router.map(function() { + this.resource("photoGallery", {path: "hamster-photos/:photo_id"}, function() { + this.route("comment", {path: "comments/:comment_id"}); + }); + }); + ``` + This argument will become the model context of the linked route: + + ```handlebars + {{#link-to 'photoGallery.comment' aPhoto comment}} + {{comment.body}} + {{/link-to}} + ``` + + ```html + + A+++ would snuggle again. + + ``` + + ### Supplying an explicit dynamic segment value + If you don't have a model object available to pass to `{{link-to}}`, + an optional string or integer argument can be passed for routes whose + paths contain dynamic segments. This argument will become the value + of the dynamic segment: + + ```javascript + App.Router.map(function() { + this.resource("photoGallery", {path: "hamster-photos/:photo_id"}); + }); + ``` + + ```handlebars + {{#link-to 'photoGallery' aPhotoId}} + {{aPhoto.title}} + {{/link-to}} + ``` + + ```html + + Tomster + + ``` + + When transitioning into the linked route, the `model` hook will + be triggered with parameters including this passed identifier. + + ### Overriding attributes + You can override any given property of the Ember.LinkView + that is generated by the `{{link-to}}` helper by passing + key/value pairs, like so: + + ```handlebars + {{#link-to aPhoto tagName='li' title='Following this link will change your life' classNames=['pic', 'sweet']}} + Uh-mazing! + {{/link-to}} + ``` + + See [Ember.LinkView](/api/classes/Ember.LinkView.html) for a + complete list of overrideable properties. Be sure to also + check out inherited properties of `LinkView`. + + ### Overriding Application-wide Defaults + ``{{link-to}}`` creates an instance of Ember.LinkView + for rendering. To override options for your entire + application, reopen Ember.LinkView and supply the + desired values: + + ``` javascript + Ember.LinkView.reopen({ + activeClass: "is-active", + tagName: 'li' + }) + ``` + + It is also possible to override the default event in + this manner: + + ``` javascript + Ember.LinkView.reopen({ + eventName: 'customEventName' + }); + ``` + + @method link-to + @for Ember.Handlebars.helpers + @param {String} routeName + @param {Object} [context]* + @param [options] {Object} Handlebars key/value pairs of options, you can override any property of Ember.LinkView + @return {String} HTML string + @see {Ember.LinkView} + */ + Ember.Handlebars.registerHelper('link-to', function(name) { + var options = [].slice.call(arguments, -1)[0], + params = [].slice.call(arguments, 0, -1), + hash = options.hash; + + hash.disabledBinding = hash.disabledWhen; + + + if (!options.fn) { + var linkTitle = params.shift(); + var linkType = options.types.shift(); + var context = this; + if (linkType === 'ID') { + options.linkTextPath = linkTitle; + options.fn = function() { + return Ember.Handlebars.get(context, linkTitle, options); + }; + } else { + options.fn = function() { + return linkTitle; + }; + } + } + + + hash.parameters = { + context: this, + options: options, + params: params + }; + + return Ember.Handlebars.helpers.view.call(this, LinkView, options); + }); + + /** + See [link-to](/api/classes/Ember.Handlebars.helpers.html#method_link-to) + + @method linkTo + @for Ember.Handlebars.helpers + @deprecated + @param {String} routeName + @param {Object} [context]* + @return {String} HTML string + */ + Ember.Handlebars.registerHelper('linkTo', Ember.Handlebars.helpers['link-to']); +}); + + + +})(); + + + +(function() { +/** +@module ember +@submodule ember-routing +*/ + +var get = Ember.get, set = Ember.set; +Ember.onLoad('Ember.Handlebars', function(Handlebars) { + /** + @module ember + @submodule ember-routing + */ + + Handlebars.OutletView = Ember.ContainerView.extend(Ember._Metamorph); + + /** + The `outlet` helper is a placeholder that the router will fill in with + the appropriate template based on the current state of the application. + + ``` handlebars + {{outlet}} + ``` + + By default, a template based on Ember's naming conventions will be rendered + into the `outlet` (e.g. `App.PostsRoute` will render the `posts` template). + + You can render a different template by using the `render()` method in the + route's `renderTemplate` hook. The following will render the `favoritePost` + template into the `outlet`. + + ``` javascript + App.PostsRoute = Ember.Route.extend({ + renderTemplate: function() { + this.render('favoritePost'); + } + }); + ``` + + You can create custom named outlets for more control. + + ``` handlebars + {{outlet 'favoritePost'}} + {{outlet 'posts'}} + ``` + + Then you can define what template is rendered into each outlet in your + route. + + + ``` javascript + App.PostsRoute = Ember.Route.extend({ + renderTemplate: function() { + this.render('favoritePost', { outlet: 'favoritePost' }); + this.render('posts', { outlet: 'posts' }); + } + }); + ``` + + You can specify the view class that the outlet uses to contain and manage the + templates rendered into it. + + ``` handlebars + {{outlet viewClass=App.SectionContainer}} + ``` + + ``` javascript + App.SectionContainer = Ember.ContainerView.extend({ + tagName: 'section', + classNames: ['special'] + }); + ``` + + @method outlet + @for Ember.Handlebars.helpers + @param {String} property the property on the controller + that holds the view for this outlet + @return {String} HTML string + */ + Handlebars.registerHelper('outlet', function(property, options) { + var outletSource, outletContainerClass; + + if (property && property.data && property.data.isRenderData) { + options = property; + property = 'main'; + } + + outletSource = options.data.view; + while (!outletSource.get('template.isTop')) { + outletSource = outletSource.get('_parentView'); + } + + outletContainerClass = options.hash.viewClass || Handlebars.OutletView; + + options.data.view.set('outletSource', outletSource); + options.hash.currentViewBinding = '_view.outletSource._outlets.' + property; + + return Handlebars.helpers.view.call(this, outletContainerClass, options); + }); +}); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-routing +*/ + +var get = Ember.get, set = Ember.set; +Ember.onLoad('Ember.Handlebars', function(Handlebars) { + + /** + Calling ``{{render}}`` from within a template will insert another + template that matches the provided name. The inserted template will + access its properties on its own controller (rather than the controller + of the parent template). + + If a view class with the same name exists, the view class also will be used. + + Note: A given controller may only be used *once* in your app in this manner. + A singleton instance of the controller will be created for you. + + Example: + + ```javascript + App.NavigationController = Ember.Controller.extend({ + who: "world" + }); + ``` + + ```handlebars + + Hello, {{who}}. + ``` + + ```handelbars + +

    My great app

    + {{render navigation}} + ``` + + ```html +

    My great app

    +
    + Hello, world. +
    + ``` + + Optionally you may provide a second argument: a property path + that will be bound to the `model` property of the controller. + + If a `model` property path is specified, then a new instance of the + controller will be created and `{{render}}` can be used multiple times + with the same name. + + For example if you had this `author` template. + + ```handlebars +
    + Written by {{firstName}} {{lastName}}. + Total Posts: {{postCount}} +
    + ``` + + You could render it inside the `post` template using the `render` helper. + + ```handlebars +
    +

    {{title}}

    +
    {{body}}
    + {{render "author" author}} +
    + ``` + + @method render + @for Ember.Handlebars.helpers + @param {String} name + @param {Object?} contextString + @param {Hash} options + @return {String} HTML string + */ + Ember.Handlebars.registerHelper('render', function(name, contextString, options) { + Ember.assert("You must pass a template to render", arguments.length >= 2); + var contextProvided = arguments.length === 3, + container, router, controller, view, context, lookupOptions; + + if (arguments.length === 2) { + options = contextString; + contextString = undefined; + } + + if (typeof contextString === 'string') { + context = Ember.Handlebars.get(options.contexts[1], contextString, options); + lookupOptions = { singleton: false }; + } + + name = name.replace(/\//g, '.'); + container = options.data.keywords.controller.container; + router = container.lookup('router:main'); + + Ember.assert("You can only use the {{render}} helper once without a model object as its second argument, as in {{render \"post\" post}}.", contextProvided || !router || !router._lookupActiveView(name)); + + view = container.lookup('view:' + name) || container.lookup('view:default'); + + var controllerName = options.hash.controller; + + // Look up the controller by name, if provided. + if (controllerName) { + controller = container.lookup('controller:' + controllerName, lookupOptions); + Ember.assert("The controller name you supplied '" + controllerName + "' did not resolve to a controller.", !!controller); + } else { + controller = container.lookup('controller:' + name, lookupOptions) || + Ember.generateController(container, name, context); + } + + if (controller && contextProvided) { + controller.set('model', context); + } + + var root = options.contexts[1]; + + if (root) { + view.registerObserver(root, contextString, function() { + controller.set('model', Ember.Handlebars.get(root, contextString, options)); + }); + } + + controller.set('target', options.data.keywords.controller); + + options.hash.viewName = Ember.String.camelize(name); + options.hash.template = container.lookup('template:' + name); + options.hash.controller = controller; + + if (router && !context) { + router._connectActiveView(name, view); + } + + Ember.Handlebars.helpers.view.call(this, view, options); + }); + +}); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-routing +*/ +Ember.onLoad('Ember.Handlebars', function(Handlebars) { + + var resolveParams = Ember.Router.resolveParams, + isSimpleClick = Ember.ViewUtils.isSimpleClick; + + var EmberHandlebars = Ember.Handlebars, + handlebarsGet = EmberHandlebars.get, + SafeString = EmberHandlebars.SafeString, + forEach = Ember.ArrayPolyfills.forEach, + get = Ember.get, + a_slice = Array.prototype.slice; + + function args(options, actionName) { + var ret = []; + if (actionName) { ret.push(actionName); } + + var types = options.options.types.slice(1), + data = options.options.data; + + return ret.concat(resolveParams(options.context, options.params, { types: types, data: data })); + } + + var ActionHelper = EmberHandlebars.ActionHelper = { + registeredActions: {} + }; + + var keys = ["alt", "shift", "meta", "ctrl"]; + + var POINTER_EVENT_TYPE_REGEX = /^click|mouse|touch/; + + var isAllowedEvent = function(event, allowedKeys) { + if (typeof allowedKeys === "undefined") { + if (POINTER_EVENT_TYPE_REGEX.test(event.type)) { + return isSimpleClick(event); + } else { + allowedKeys = []; + } + } + + if (allowedKeys.indexOf("any") >= 0) { + return true; + } + + var allowed = true; + + forEach.call(keys, function(key) { + if (event[key + "Key"] && allowedKeys.indexOf(key) === -1) { + allowed = false; + } + }); + + return allowed; + }; + + ActionHelper.registerAction = function(actionName, options, allowedKeys) { + var actionId = (++Ember.uuid).toString(); + + ActionHelper.registeredActions[actionId] = { + eventName: options.eventName, + handler: function(event) { + if (!isAllowedEvent(event, allowedKeys)) { return true; } + + event.preventDefault(); + + if (options.bubbles === false) { + event.stopPropagation(); + } + + var target = options.target; + + if (target.target) { + target = handlebarsGet(target.root, target.target, target.options); + } else { + target = target.root; + } + + Ember.run(function() { + if (target.send) { + target.send.apply(target, args(options.parameters, actionName)); + } else { + Ember.assert("The action '" + actionName + "' did not exist on " + target, typeof target[actionName] === 'function'); + target[actionName].apply(target, args(options.parameters)); + } + }); + } + }; + + options.view.on('willClearRender', function() { + delete ActionHelper.registeredActions[actionId]; + }); + + return actionId; + }; + + /** + The `{{action}}` helper registers an HTML element within a template for DOM + event handling and forwards that interaction to the templates's controller + or supplied `target` option (see 'Specifying a Target'). + + If the controller does not implement the event, the event is sent + to the current route, and it bubbles up the route hierarchy from there. + + User interaction with that element will invoke the supplied action name on + the appropriate target. + + Given the following application Handlebars template on the page + + ```handlebars +
    + click me +
    + ``` + + And application code + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + actions: { + anActionName: function() { + + } + } + }); + ``` + + Will result in the following rendered HTML + + ```html +
    +
    + click me +
    +
    + ``` + + Clicking "click me" will trigger the `anActionName` action of the + `App.ApplicationController`. In this case, no additional parameters will be passed. + + If you provide additional parameters to the helper: + + ```handlebars + + ``` + + Those parameters will be passed along as arguments to the JavaScript + function implementing the action. + + ### Event Propagation + + Events triggered through the action helper will automatically have + `.preventDefault()` called on them. You do not need to do so in your event + handlers. + + To also disable bubbling, pass `bubbles=false` to the helper: + + ```handlebars + + ``` + + If you need the default handler to trigger you should either register your + own event handler, or use event methods on your view class. See [Ember.View](/api/classes/Ember.View.html) + 'Responding to Browser Events' for more information. + + ### Specifying DOM event type + + By default the `{{action}}` helper registers for DOM `click` events. You can + supply an `on` option to the helper to specify a different DOM event name: + + ```handlebars +
    + click me +
    + ``` + + See `Ember.View` 'Responding to Browser Events' for a list of + acceptable DOM event names. + + NOTE: Because `{{action}}` depends on Ember's event dispatch system it will + only function if an `Ember.EventDispatcher` instance is available. An + `Ember.EventDispatcher` instance will be created when a new `Ember.Application` + is created. Having an instance of `Ember.Application` will satisfy this + requirement. + + ### Specifying whitelisted modifier keys + + By default the `{{action}}` helper will ignore click event with pressed modifier + keys. You can supply an `allowedKeys` option to specify which keys should not be ignored. + + ```handlebars +
    + click me +
    + ``` + + This way the `{{action}}` will fire when clicking with the alt key pressed down. + + Alternatively, supply "any" to the `allowedKeys` option to accept any combination of modifier keys. + + ```handlebars +
    + click me with any key pressed +
    + ``` + + ### Specifying a Target + + There are several possible target objects for `{{action}}` helpers: + + In a typical Ember application, where views are managed through use of the + `{{outlet}}` helper, actions will bubble to the current controller, then + to the current route, and then up the route hierarchy. + + Alternatively, a `target` option can be provided to the helper to change + which object will receive the method call. This option must be a path + to an object, accessible in the current context: + + ```handlebars + {{! the application template }} +
    + click me +
    + ``` + + ```javascript + App.ApplicationView = Ember.View.extend({ + actions: { + anActionName: function(){} + } + }); + + ``` + + ### Additional Parameters + + You may specify additional parameters to the `{{action}}` helper. These + parameters are passed along as the arguments to the JavaScript function + implementing the action. + + ```handlebars + {{#each person in people}} +
    + click me +
    + {{/each}} + ``` + + Clicking "click me" will trigger the `edit` method on the current controller + with the value of `person` as a parameter. + + @method action + @for Ember.Handlebars.helpers + @param {String} actionName + @param {Object} [context]* + @param {Hash} options + */ + EmberHandlebars.registerHelper('action', function(actionName) { + var options = arguments[arguments.length - 1], + contexts = a_slice.call(arguments, 1, -1); + + var hash = options.hash, + controller; + + // create a hash to pass along to registerAction + var action = { + eventName: hash.on || "click" + }; + + action.parameters = { + context: this, + options: options, + params: contexts + }; + + action.view = options.data.view; + + var root, target; + + if (hash.target) { + root = this; + target = hash.target; + } else if (controller = options.data.keywords.controller) { + root = controller; + } + + action.target = { root: root, target: target, options: options }; + action.bubbles = hash.bubbles; + + var actionId = ActionHelper.registerAction(actionName, action, hash.allowedKeys); + return new SafeString('data-ember-action="' + actionId + '"'); + }); + +}); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-routing +*/ + +if (Ember.ENV.EXPERIMENTAL_CONTROL_HELPER) { + var get = Ember.get, set = Ember.set; + + /** + `{{control}}` works like render, except it uses a new controller instance for every call, instead of reusing the singleton controller. + + The control helper is currently under development and is considered experimental. + To enable it, set `ENV.EXPERIMENTAL_CONTROL_HELPER = true` before requiring Ember. + + For example if you had this `author` template. + + ```handlebars +
    + Written by {{firstName}} {{lastName}}. + Total Posts: {{postCount}} +
    + ``` + + You could render it inside the `post` template using the `control` helper. + + ```handlebars +
    +

    {{title}}

    +
    {{body}}
    + {{control "author" author}} +
    + ``` + + @method control + @for Ember.Handlebars.helpers + @param {String} path + @param {String} modelPath + @param {Hash} options + @return {String} HTML string + */ + Ember.Handlebars.registerHelper('control', function(path, modelPath, options) { + if (arguments.length === 2) { + options = modelPath; + modelPath = undefined; + } + + var model; + + if (modelPath) { + model = Ember.Handlebars.get(this, modelPath, options); + } + + var controller = options.data.keywords.controller, + view = options.data.keywords.view, + children = get(controller, '_childContainers'), + controlID = options.hash.controlID, + container, subContainer; + + if (children.hasOwnProperty(controlID)) { + subContainer = children[controlID]; + } else { + container = get(controller, 'container'), + subContainer = container.child(); + children[controlID] = subContainer; + } + + var normalizedPath = path.replace(/\//g, '.'); + + var childView = subContainer.lookup('view:' + normalizedPath) || subContainer.lookup('view:default'), + childController = subContainer.lookup('controller:' + normalizedPath), + childTemplate = subContainer.lookup('template:' + path); + + Ember.assert("Could not find controller for path: " + normalizedPath, childController); + Ember.assert("Could not find view for path: " + normalizedPath, childView); + + set(childController, 'target', controller); + set(childController, 'model', model); + + options.hash.template = childTemplate; + options.hash.controller = childController; + + function observer() { + var model = Ember.Handlebars.get(this, modelPath, options); + set(childController, 'model', model); + childView.rerender(); + } + + if (modelPath) { + Ember.addObserver(this, modelPath, observer); + childView.one('willDestroyElement', this, function() { + Ember.removeObserver(this, modelPath, observer); + }); + } + + Ember.Handlebars.helpers.view.call(this, childView, options); + }); +} + +})(); + + + +(function() { + +})(); + + + +(function() { +/** +@module ember +@submodule ember-routing +*/ + +var get = Ember.get, set = Ember.set; + +Ember.ControllerMixin.reopen({ + /** + Transition the application into another route. The route may + be either a single route or route path: + + ```javascript + aController.transitionToRoute('blogPosts'); + aController.transitionToRoute('blogPosts.recentEntries'); + ``` + + Optionally supply a model for the route in question. The model + will be serialized into the URL using the `serialize` hook of + the route: + + ```javascript + aController.transitionToRoute('blogPost', aPost); + ``` + + Multiple models will be applied last to first recursively up the + resource tree. + + ```javascript + + this.resource('blogPost', {path:':blogPostId'}, function(){ + this.resource('blogComment', {path: ':blogCommentId'}); + }); + + aController.transitionToRoute('blogComment', aPost, aComment); + ``` + + See also 'replaceRoute'. + + @param {String} name the name of the route + @param {...Object} models the model(s) to be used while transitioning + to the route. + @for Ember.ControllerMixin + @method transitionToRoute + */ + transitionToRoute: function() { + // target may be either another controller or a router + var target = get(this, 'target'), + method = target.transitionToRoute || target.transitionTo; + return method.apply(target, arguments); + }, + + /** + @deprecated + @for Ember.ControllerMixin + @method transitionTo + */ + transitionTo: function() { + Ember.deprecate("transitionTo is deprecated. Please use transitionToRoute."); + return this.transitionToRoute.apply(this, arguments); + }, + + /** + Transition into another route while replacing the current URL, if possible. + This will replace the current history entry instead of adding a new one. + Beside that, it is identical to `transitionToRoute` in all other respects. + + ```javascript + aController.replaceRoute('blogPosts'); + aController.replaceRoute('blogPosts.recentEntries'); + ``` + + Optionally supply a model for the route in question. The model + will be serialized into the URL using the `serialize` hook of + the route: + + ```javascript + aController.replaceRoute('blogPost', aPost); + ``` + + Multiple models will be applied last to first recursively up the + resource tree. + + ```javascript + + this.resource('blogPost', {path:':blogPostId'}, function(){ + this.resource('blogComment', {path: ':blogCommentId'}); + }); + + aController.replaceRoute('blogComment', aPost, aComment); + ``` + + @param {String} name the name of the route + @param {...Object} models the model(s) to be used while transitioning + to the route. + @for Ember.ControllerMixin + @method replaceRoute + */ + replaceRoute: function() { + // target may be either another controller or a router + var target = get(this, 'target'), + method = target.replaceRoute || target.replaceWith; + return method.apply(target, arguments); + }, + + /** + @deprecated + @for Ember.ControllerMixin + @method replaceWith + */ + replaceWith: function() { + Ember.deprecate("replaceWith is deprecated. Please use replaceRoute."); + return this.replaceRoute.apply(this, arguments); + } +}); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-routing +*/ + +var get = Ember.get, set = Ember.set; + +Ember.View.reopen({ + + /** + Sets the private `_outlets` object on the view. + + @method init + */ + init: function() { + set(this, '_outlets', {}); + this._super(); + }, + + /** + Manually fill any of a view's `{{outlet}}` areas with the + supplied view. + + Example + + ```javascript + var MyView = Ember.View.extend({ + template: Ember.Handlebars.compile('Child view: {{outlet "main"}} ') + }); + var myView = MyView.create(); + myView.appendTo('body'); + // The html for myView now looks like: + //
    Child view:
    + + myView.connectOutlet('main', Ember.View.extend({ + template: Ember.Handlebars.compile('

    Foo

    ') + })); + // The html for myView now looks like: + //
    Child view: + //

    Foo

    + //
    + ``` + @method connectOutlet + @param {String} outletName A unique name for the outlet + @param {Object} view An Ember.View + */ + connectOutlet: function(outletName, view) { + if (this._pendingDisconnections) { + delete this._pendingDisconnections[outletName]; + } + + if (this._hasEquivalentView(outletName, view)) { + view.destroy(); + return; + } + + var outlets = get(this, '_outlets'), + container = get(this, 'container'), + router = container && container.lookup('router:main'), + renderedName = get(view, 'renderedName'); + + set(outlets, outletName, view); + + if (router && renderedName) { + router._connectActiveView(renderedName, view); + } + }, + + /** + @private + + Determines if the view has already been created by checking if + the view has the same constructor, template, and context as the + view in the `_outlets` object. + + @method _hasEquivalentView + @param {String} outletName The name of the outlet we are checking + @param {Object} view An Ember.View + @return {Boolean} + */ + _hasEquivalentView: function(outletName, view) { + var existingView = get(this, '_outlets.'+outletName); + return existingView && + existingView.constructor === view.constructor && + existingView.get('template') === view.get('template') && + existingView.get('context') === view.get('context'); + }, + + /** + Removes an outlet from the view. + + Example + + ```javascript + var MyView = Ember.View.extend({ + template: Ember.Handlebars.compile('Child view: {{outlet "main"}} ') + }); + var myView = MyView.create(); + myView.appendTo('body'); + // myView's html: + //
    Child view:
    + + myView.connectOutlet('main', Ember.View.extend({ + template: Ember.Handlebars.compile('

    Foo

    ') + })); + // myView's html: + //
    Child view: + //

    Foo

    + //
    + + myView.disconnectOutlet('main'); + // myView's html: + //
    Child view:
    + ``` + + @method disconnectOutlet + @param {String} outletName The name of the outlet to be removed + */ + disconnectOutlet: function(outletName) { + if (!this._pendingDisconnections) { + this._pendingDisconnections = {}; + } + this._pendingDisconnections[outletName] = true; + Ember.run.once(this, '_finishDisconnections'); + }, + + /** + @private + + Gets an outlet that is pending disconnection and then + nullifys the object on the `_outlet` object. + + @method _finishDisconnections + */ + _finishDisconnections: function() { + var outlets = get(this, '_outlets'); + var pendingDisconnections = this._pendingDisconnections; + this._pendingDisconnections = null; + + for (var outletName in pendingDisconnections) { + set(outlets, outletName, null); + } + } +}); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-views +*/ + +// Add a new named queue after the 'actions' queue (where RSVP promises +// resolve), which is used in router transitions to prevent unnecessary +// loading state entry if all context promises resolve on the +// 'actions' queue first. + +var queues = Ember.run.queues, + indexOf = Ember.ArrayPolyfills.indexOf; +queues.splice(indexOf.call(queues, 'actions') + 1, 0, 'routerTransitions'); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-routing +*/ + +var get = Ember.get, set = Ember.set; + +/* + This file implements the `location` API used by Ember's router. + + That API is: + + getURL: returns the current URL + setURL(path): sets the current URL + replaceURL(path): replace the current URL (optional) + onUpdateURL(callback): triggers the callback when the URL changes + formatURL(url): formats `url` to be placed into `href` attribute + + Calling setURL or replaceURL will not trigger onUpdateURL callbacks. + + TODO: This should perhaps be moved so that it's visible in the doc output. +*/ + +/** + Ember.Location returns an instance of the correct implementation of + the `location` API. + + You can pass it a `implementation` ('hash', 'history', 'none') to force a + particular implementation. + + @class Location + @namespace Ember + @static +*/ +Ember.Location = { + /** + Create an instance of a an implementation of the `location` API. Requires + an options object with an `implementation` property. + + Example + + ```javascript + var hashLocation = Ember.Location.create({implementation: 'hash'}); + var historyLocation = Ember.Location.create({implementation: 'history'}); + var noneLocation = Ember.Location.create({implementation: 'none'}); + ``` + + @method create + @param {Object} options + @return {Object} an instance of an implementation of the `location` API + */ + create: function(options) { + var implementation = options && options.implementation; + Ember.assert("Ember.Location.create: you must specify a 'implementation' option", !!implementation); + + var implementationClass = this.implementations[implementation]; + Ember.assert("Ember.Location.create: " + implementation + " is not a valid implementation", !!implementationClass); + + return implementationClass.create.apply(implementationClass, arguments); + }, + + /** + Registers a class that implements the `location` API with an implementation + name. This implementation name can then be specified by the location property on + the application's router class. + + Example + + ```javascript + Ember.Location.registerImplementation('history', Ember.HistoryLocation); + + App.Router.reopen({ + location: 'history' + }); + ``` + + @method registerImplementation + @param {String} name + @param {Object} implementation of the `location` API + */ + registerImplementation: function(name, implementation) { + this.implementations[name] = implementation; + }, + + implementations: {} +}; + +})(); + + + +(function() { +/** +@module ember +@submodule ember-routing +*/ + +var get = Ember.get, set = Ember.set; + +/** + Ember.NoneLocation does not interact with the browser. It is useful for + testing, or when you need to manage state with your Router, but temporarily + don't want it to muck with the URL (for example when you embed your + application in a larger page). + + @class NoneLocation + @namespace Ember + @extends Ember.Object +*/ +Ember.NoneLocation = Ember.Object.extend({ + path: '', + + /** + @private + + Returns the current path. + + @method getURL + @return {String} path + */ + getURL: function() { + return get(this, 'path'); + }, + + /** + @private + + Set the path and remembers what was set. Using this method + to change the path will not invoke the `updateURL` callback. + + @method setURL + @param path {String} + */ + setURL: function(path) { + set(this, 'path', path); + }, + + /** + @private + + Register a callback to be invoked when the path changes. These + callbacks will execute when the user presses the back or forward + button, but not after `setURL` is invoked. + + @method onUpdateURL + @param callback {Function} + */ + onUpdateURL: function(callback) { + this.updateCallback = callback; + }, + + /** + @private + + Sets the path and calls the `updateURL` callback. + + @method handleURL + @param callback {Function} + */ + handleURL: function(url) { + set(this, 'path', url); + this.updateCallback(url); + }, + + /** + @private + + Given a URL, formats it to be placed into the page as part + of an element's `href` attribute. + + This is used, for example, when using the {{action}} helper + to generate a URL based on an event. + + @method formatURL + @param url {String} + @return {String} url + */ + formatURL: function(url) { + // The return value is not overly meaningful, but we do not want to throw + // errors when test code renders templates containing {{action href=true}} + // helpers. + return url; + } +}); + +Ember.Location.registerImplementation('none', Ember.NoneLocation); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-routing +*/ + +var get = Ember.get, set = Ember.set; + +/** + Ember.HashLocation implements the location API using the browser's + hash. At present, it relies on a hashchange event existing in the + browser. + + @class HashLocation + @namespace Ember + @extends Ember.Object +*/ +Ember.HashLocation = Ember.Object.extend({ + + init: function() { + set(this, 'location', get(this, 'location') || window.location); + }, + + /** + @private + + Returns the current `location.hash`, minus the '#' at the front. + + @method getURL + */ + getURL: function() { + // Default implementation without feature flag enabled + return get(this, 'location').hash.substr(1); + }, + + /** + @private + + Set the `location.hash` and remembers what was set. This prevents + `onUpdateURL` callbacks from triggering when the hash was set by + `HashLocation`. + + @method setURL + @param path {String} + */ + setURL: function(path) { + get(this, 'location').hash = path; + set(this, 'lastSetURL', path); + }, + + /** + @private + + Uses location.replace to update the url without a page reload + or history modification. + + @method replaceURL + @param path {String} + */ + replaceURL: function(path) { + get(this, 'location').replace('#' + path); + }, + + /** + @private + + Register a callback to be invoked when the hash changes. These + callbacks will execute when the user presses the back or forward + button, but not after `setURL` is invoked. + + @method onUpdateURL + @param callback {Function} + */ + onUpdateURL: function(callback) { + var self = this; + var guid = Ember.guidFor(this); + + Ember.$(window).on('hashchange.ember-location-'+guid, function() { + Ember.run(function() { + var path = location.hash.substr(1); + if (get(self, 'lastSetURL') === path) { return; } + + set(self, 'lastSetURL', null); + + callback(path); + }); + }); + }, + + /** + @private + + Given a URL, formats it to be placed into the page as part + of an element's `href` attribute. + + This is used, for example, when using the {{action}} helper + to generate a URL based on an event. + + @method formatURL + @param url {String} + */ + formatURL: function(url) { + return '#'+url; + }, + + /** + @private + + Cleans up the HashLocation event listener. + + @method willDestroy + */ + willDestroy: function() { + var guid = Ember.guidFor(this); + + Ember.$(window).off('hashchange.ember-location-'+guid); + } +}); + +Ember.Location.registerImplementation('hash', Ember.HashLocation); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-routing +*/ + +var get = Ember.get, set = Ember.set; +var popstateFired = false; +var supportsHistoryState = window.history && 'state' in window.history; + +/** + Ember.HistoryLocation implements the location API using the browser's + history.pushState API. + + @class HistoryLocation + @namespace Ember + @extends Ember.Object +*/ +Ember.HistoryLocation = Ember.Object.extend({ + + init: function() { + set(this, 'location', get(this, 'location') || window.location); + this.initState(); + }, + + /** + @private + + Used to set state on first call to setURL + + @method initState + */ + initState: function() { + set(this, 'history', get(this, 'history') || window.history); + this.replaceState(this.formatURL(this.getURL())); + }, + + /** + Will be pre-pended to path upon state change + + @property rootURL + @default '/' + */ + rootURL: '/', + + /** + @private + + Returns the current `location.pathname` without rootURL + + @method getURL + @return url {String} + */ + getURL: function() { + var rootURL = get(this, 'rootURL'), + location = get(this, 'location'), + path = location.pathname; + + rootURL = rootURL.replace(/\/$/, ''); + var url = path.replace(rootURL, ''); + + + return url; + }, + + /** + @private + + Uses `history.pushState` to update the url without a page reload. + + @method setURL + @param path {String} + */ + setURL: function(path) { + var state = this.getState(); + path = this.formatURL(path); + + if (state && state.path !== path) { + this.pushState(path); + } + }, + + /** + @private + + Uses `history.replaceState` to update the url without a page reload + or history modification. + + @method replaceURL + @param path {String} + */ + replaceURL: function(path) { + var state = this.getState(); + path = this.formatURL(path); + + if (state && state.path !== path) { + this.replaceState(path); + } + }, + + /** + @private + + Get the current `history.state` + Polyfill checks for native browser support and falls back to retrieving + from a private _historyState variable + + @method getState + @return state {Object} + */ + getState: function() { + return supportsHistoryState ? get(this, 'history').state : this._historyState; + }, + + /** + @private + + Pushes a new state + + @method pushState + @param path {String} + */ + pushState: function(path) { + var state = { path: path }; + + get(this, 'history').pushState(state, null, path); + + // store state if browser doesn't support `history.state` + if (!supportsHistoryState) { + this._historyState = state; + } + + // used for webkit workaround + this._previousURL = this.getURL(); + }, + + /** + @private + + Replaces the current state + + @method replaceState + @param path {String} + */ + replaceState: function(path) { + var state = { path: path }; + + get(this, 'history').replaceState(state, null, path); + + // store state if browser doesn't support `history.state` + if (!supportsHistoryState) { + this._historyState = state; + } + + // used for webkit workaround + this._previousURL = this.getURL(); + }, + + /** + @private + + Register a callback to be invoked whenever the browser + history changes, including using forward and back buttons. + + @method onUpdateURL + @param callback {Function} + */ + onUpdateURL: function(callback) { + var guid = Ember.guidFor(this), + self = this; + + Ember.$(window).on('popstate.ember-location-'+guid, function(e) { + // Ignore initial page load popstate event in Chrome + if (!popstateFired) { + popstateFired = true; + if (self.getURL() === self._previousURL) { return; } + } + callback(self.getURL()); + }); + }, + + /** + @private + + Used when using `{{action}}` helper. The url is always appended to the rootURL. + + @method formatURL + @param url {String} + @return formatted url {String} + */ + formatURL: function(url) { + var rootURL = get(this, 'rootURL'); + + if (url !== '') { + rootURL = rootURL.replace(/\/$/, ''); + } + + return rootURL + url; + }, + + /** + @private + + Cleans up the HistoryLocation event listener. + + @method willDestroy + */ + willDestroy: function() { + var guid = Ember.guidFor(this); + + Ember.$(window).off('popstate.ember-location-'+guid); + } +}); + +Ember.Location.registerImplementation('history', Ember.HistoryLocation); + +})(); + + + +(function() { + +})(); + + + +(function() { +/** +Ember Routing + +@module ember +@submodule ember-routing +@requires ember-views +*/ + +})(); + +(function() { +function visit(vertex, fn, visited, path) { + var name = vertex.name, + vertices = vertex.incoming, + names = vertex.incomingNames, + len = names.length, + i; + if (!visited) { + visited = {}; + } + if (!path) { + path = []; + } + if (visited.hasOwnProperty(name)) { + return; + } + path.push(name); + visited[name] = true; + for (i = 0; i < len; i++) { + visit(vertices[names[i]], fn, visited, path); + } + fn(vertex, path); + path.pop(); +} + +function DAG() { + this.names = []; + this.vertices = {}; +} + +DAG.prototype.add = function(name) { + if (!name) { return; } + if (this.vertices.hasOwnProperty(name)) { + return this.vertices[name]; + } + var vertex = { + name: name, incoming: {}, incomingNames: [], hasOutgoing: false, value: null + }; + this.vertices[name] = vertex; + this.names.push(name); + return vertex; +}; + +DAG.prototype.map = function(name, value) { + this.add(name).value = value; +}; + +DAG.prototype.addEdge = function(fromName, toName) { + if (!fromName || !toName || fromName === toName) { + return; + } + var from = this.add(fromName), to = this.add(toName); + if (to.incoming.hasOwnProperty(fromName)) { + return; + } + function checkCycle(vertex, path) { + if (vertex.name === toName) { + throw new Ember.Error("cycle detected: " + toName + " <- " + path.join(" <- ")); + } + } + visit(from, checkCycle); + from.hasOutgoing = true; + to.incoming[fromName] = from; + to.incomingNames.push(fromName); +}; + +DAG.prototype.topsort = function(fn) { + var visited = {}, + vertices = this.vertices, + names = this.names, + len = names.length, + i, vertex; + for (i = 0; i < len; i++) { + vertex = vertices[names[i]]; + if (!vertex.hasOutgoing) { + visit(vertex, fn, visited); + } + } +}; + +DAG.prototype.addEdges = function(name, value, before, after) { + var i; + this.map(name, value); + if (before) { + if (typeof before === 'string') { + this.addEdge(name, before); + } else { + for (i = 0; i < before.length; i++) { + this.addEdge(name, before[i]); + } + } + } + if (after) { + if (typeof after === 'string') { + this.addEdge(after, name); + } else { + for (i = 0; i < after.length; i++) { + this.addEdge(after[i], name); + } + } + } +}; + +Ember.DAG = DAG; + +})(); + + + +(function() { +/** +@module ember +@submodule ember-application +*/ + +var get = Ember.get, + classify = Ember.String.classify, + capitalize = Ember.String.capitalize, + decamelize = Ember.String.decamelize; + +/** + The DefaultResolver defines the default lookup rules to resolve + container lookups before consulting the container for registered + items: + +* templates are looked up on `Ember.TEMPLATES` +* other names are looked up on the application after converting + the name. For example, `controller:post` looks up + `App.PostController` by default. +* there are some nuances (see examples below) + + ### How Resolving Works + + The container calls this object's `resolve` method with the + `fullName` argument. + + It first parses the fullName into an object using `parseName`. + + Then it checks for the presence of a type-specific instance + method of the form `resolve[Type]` and calls it if it exists. + For example if it was resolving 'template:post', it would call + the `resolveTemplate` method. + + Its last resort is to call the `resolveOther` method. + + The methods of this object are designed to be easy to override + in a subclass. For example, you could enhance how a template + is resolved like so: + + ```javascript + App = Ember.Application.create({ + Resolver: Ember.DefaultResolver.extend({ + resolveTemplate: function(parsedName) { + var resolvedTemplate = this._super(parsedName); + if (resolvedTemplate) { return resolvedTemplate; } + return Ember.TEMPLATES['not_found']; + } + }) + }); + ``` + + Some examples of how names are resolved: + + ``` + 'template:post' //=> Ember.TEMPLATES['post'] + 'template:posts/byline' //=> Ember.TEMPLATES['posts/byline'] + 'template:posts.byline' //=> Ember.TEMPLATES['posts/byline'] + 'template:blogPost' //=> Ember.TEMPLATES['blogPost'] + // OR + // Ember.TEMPLATES['blog_post'] + 'controller:post' //=> App.PostController + 'controller:posts.index' //=> App.PostsIndexController + 'controller:blog/post' //=> Blog.PostController + 'controller:basic' //=> Ember.Controller + 'route:post' //=> App.PostRoute + 'route:posts.index' //=> App.PostsIndexRoute + 'route:blog/post' //=> Blog.PostRoute + 'route:basic' //=> Ember.Route + 'view:post' //=> App.PostView + 'view:posts.index' //=> App.PostsIndexView + 'view:blog/post' //=> Blog.PostView + 'view:basic' //=> Ember.View + 'foo:post' //=> App.PostFoo + 'model:post' //=> App.Post + ``` + + @class DefaultResolver + @namespace Ember + @extends Ember.Object +*/ +Ember.DefaultResolver = Ember.Object.extend({ + /** + This will be set to the Application instance when it is + created. + + @property namespace + */ + namespace: null, + + normalize: function(fullName) { + var split = fullName.split(':', 2), + type = split[0], + name = split[1]; + + Ember.assert("Tried to normalize a container name without a colon (:) in it. You probably tried to lookup a name that did not contain a type, a colon, and a name. A proper lookup name would be `view:post`.", split.length === 2); + + if (type !== 'template') { + var result = name; + + if (result.indexOf('.') > -1) { + result = result.replace(/\.(.)/g, function(m) { return m.charAt(1).toUpperCase(); }); + } + + if (name.indexOf('_') > -1) { + result = result.replace(/_(.)/g, function(m) { return m.charAt(1).toUpperCase(); }); + } + + return type + ':' + result; + } else { + return fullName; + } + }, + + + /** + This method is called via the container's resolver method. + It parses the provided `fullName` and then looks up and + returns the appropriate template or class. + + @method resolve + @param {String} fullName the lookup string + @return {Object} the resolved factory + */ + resolve: function(fullName) { + var parsedName = this.parseName(fullName), + typeSpecificResolveMethod = this[parsedName.resolveMethodName]; + + if (!parsedName.name || !parsedName.type) { + throw new TypeError("Invalid fullName: `" + fullName + "`, must of of the form `type:name` "); + } + + if (typeSpecificResolveMethod) { + var resolved = typeSpecificResolveMethod.call(this, parsedName); + if (resolved) { return resolved; } + } + return this.resolveOther(parsedName); + }, + /** + Convert the string name of the form "type:name" to + a Javascript object with the parsed aspects of the name + broken out. + + @protected + @param {String} fullName the lookup string + @method parseName + */ + parseName: function(fullName) { + var nameParts = fullName.split(":"), + type = nameParts[0], fullNameWithoutType = nameParts[1], + name = fullNameWithoutType, + namespace = get(this, 'namespace'), + root = namespace; + + if (type !== 'template' && name.indexOf('/') !== -1) { + var parts = name.split('/'); + name = parts[parts.length - 1]; + var namespaceName = capitalize(parts.slice(0, -1).join('.')); + root = Ember.Namespace.byName(namespaceName); + + Ember.assert('You are looking for a ' + name + ' ' + type + ' in the ' + namespaceName + ' namespace, but the namespace could not be found', root); + } + + return { + fullName: fullName, + type: type, + fullNameWithoutType: fullNameWithoutType, + name: name, + root: root, + resolveMethodName: "resolve" + classify(type) + }; + }, + /** + Look up the template in Ember.TEMPLATES + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveTemplate + */ + resolveTemplate: function(parsedName) { + var templateName = parsedName.fullNameWithoutType.replace(/\./g, '/'); + + if (Ember.TEMPLATES[templateName]) { + return Ember.TEMPLATES[templateName]; + } + + templateName = decamelize(templateName); + if (Ember.TEMPLATES[templateName]) { + return Ember.TEMPLATES[templateName]; + } + }, + /** + Given a parseName object (output from `parseName`), apply + the conventions expected by `Ember.Router` + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method useRouterNaming + */ + useRouterNaming: function(parsedName) { + parsedName.name = parsedName.name.replace(/\./g, '_'); + if (parsedName.name === 'basic') { + parsedName.name = ''; + } + }, + /** + Lookup the controller using `resolveOther` + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveController + */ + resolveController: function(parsedName) { + this.useRouterNaming(parsedName); + return this.resolveOther(parsedName); + }, + /** + Lookup the route using `resolveOther` + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveRoute + */ + resolveRoute: function(parsedName) { + this.useRouterNaming(parsedName); + return this.resolveOther(parsedName); + }, + /** + Lookup the view using `resolveOther` + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveView + */ + resolveView: function(parsedName) { + this.useRouterNaming(parsedName); + return this.resolveOther(parsedName); + }, + + resolveHelper: function(parsedName) { + return this.resolveOther(parsedName) || Ember.Handlebars.helpers[parsedName.fullNameWithoutType]; + }, + + /** + Lookup the model on the Application namespace + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveModel + */ + resolveModel: function(parsedName) { + var className = classify(parsedName.name), + factory = get(parsedName.root, className); + + if (factory) { return factory; } + }, + /** + Look up the specified object (from parsedName) on the appropriate + namespace (usually on the Application) + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveOther + */ + resolveOther: function(parsedName) { + var className = classify(parsedName.name) + classify(parsedName.type), + factory = get(parsedName.root, className); + if (factory) { return factory; } + }, + + /** + Returns a human-readable description for a fullName. Used by the + Application namespace in assertions to describe the + precise name of the class that Ember is looking for, rather than + container keys. + + @protected + @param {String} fullName the lookup string + @method lookupDescription + */ + lookupDescription: function(fullName) { + var parsedName = this.parseName(fullName); + + if (parsedName.type === 'template') { + return "template at " + parsedName.fullNameWithoutType.replace(/\./g, '/'); + } + + var description = parsedName.root + "." + classify(parsedName.name); + if (parsedName.type !== 'model') { description += classify(parsedName.type); } + + return description; + }, + + makeToString: function(factory, fullName) { + return factory.toString(); + } +}); + +})(); + + + +(function() { +/** +@module ember +@submodule ember-application +*/ + +var get = Ember.get, set = Ember.set; + +function DeprecatedContainer(container) { + this._container = container; +} + +DeprecatedContainer.deprecate = function(method) { + return function() { + var container = this._container; + + Ember.deprecate('Using the defaultContainer is no longer supported. [defaultContainer#' + method + '] see: http://git.io/EKPpnA', false); + return container[method].apply(container, arguments); + }; +}; + +DeprecatedContainer.prototype = { + _container: null, + lookup: DeprecatedContainer.deprecate('lookup'), + resolve: DeprecatedContainer.deprecate('resolve'), + register: DeprecatedContainer.deprecate('register') +}; + +/** + An instance of `Ember.Application` is the starting point for every Ember + application. It helps to instantiate, initialize and coordinate the many + objects that make up your app. + + Each Ember app has one and only one `Ember.Application` object. In fact, the + very first thing you should do in your application is create the instance: + + ```javascript + window.App = Ember.Application.create(); + ``` + + Typically, the application object is the only global variable. All other + classes in your app should be properties on the `Ember.Application` instance, + which highlights its first role: a global namespace. + + For example, if you define a view class, it might look like this: + + ```javascript + App.MyView = Ember.View.extend(); + ``` + + By default, calling `Ember.Application.create()` will automatically initialize + your application by calling the `Ember.Application.initialize()` method. If + you need to delay initialization, you can call your app's `deferReadiness()` + method. When you are ready for your app to be initialized, call its + `advanceReadiness()` method. + + You can define a `ready` method on the `Ember.Application` instance, which + will be run by Ember when the application is initialized. + + Because `Ember.Application` inherits from `Ember.Namespace`, any classes + you create will have useful string representations when calling `toString()`. + See the `Ember.Namespace` documentation for more information. + + While you can think of your `Ember.Application` as a container that holds the + other classes in your application, there are several other responsibilities + going on under-the-hood that you may want to understand. + + ### Event Delegation + + Ember uses a technique called _event delegation_. This allows the framework + to set up a global, shared event listener instead of requiring each view to + do it manually. For example, instead of each view registering its own + `mousedown` listener on its associated element, Ember sets up a `mousedown` + listener on the `body`. + + If a `mousedown` event occurs, Ember will look at the target of the event and + start walking up the DOM node tree, finding corresponding views and invoking + their `mouseDown` method as it goes. + + `Ember.Application` has a number of default events that it listens for, as + well as a mapping from lowercase events to camel-cased view method names. For + example, the `keypress` event causes the `keyPress` method on the view to be + called, the `dblclick` event causes `doubleClick` to be called, and so on. + + If there is a bubbling browser event that Ember does not listen for by + default, you can specify custom events and their corresponding view method + names by setting the application's `customEvents` property: + + ```javascript + App = Ember.Application.create({ + customEvents: { + // add support for the paste event + 'paste: "paste" + } + }); + ``` + + By default, the application sets up these event listeners on the document + body. However, in cases where you are embedding an Ember application inside + an existing page, you may want it to set up the listeners on an element + inside the body. + + For example, if only events inside a DOM element with the ID of `ember-app` + should be delegated, set your application's `rootElement` property: + + ```javascript + window.App = Ember.Application.create({ + rootElement: '#ember-app' + }); + ``` + + The `rootElement` can be either a DOM element or a jQuery-compatible selector + string. Note that *views appended to the DOM outside the root element will + not receive events.* If you specify a custom root element, make sure you only + append views inside it! + + To learn more about the advantages of event delegation and the Ember view + layer, and a list of the event listeners that are setup by default, visit the + [Ember View Layer guide](http://emberjs.com/guides/understanding-ember/the-view-layer/#toc_event-delegation). + + ### Initializers + + Libraries on top of Ember can register additional initializers, like so: + + ```javascript + Ember.Application.initializer({ + name: "store", + + initialize: function(container, application) { + container.register('store:main', application.Store); + } + }); + ``` + + ### Routing + + In addition to creating your application's router, `Ember.Application` is + also responsible for telling the router when to start routing. Transitions + between routes can be logged with the `LOG_TRANSITIONS` flag, and more + detailed intra-transition logging can be logged with + the `LOG_TRANSITIONS_INTERNAL` flag: + + ```javascript + window.App = Ember.Application.create({ + LOG_TRANSITIONS: true, // basic logging of successful transitions + LOG_TRANSITIONS_INTERNAL: true // detailed logging of all routing steps + }); + ``` + + By default, the router will begin trying to translate the current URL into + application state once the browser emits the `DOMContentReady` event. If you + need to defer routing, you can call the application's `deferReadiness()` + method. Once routing can begin, call the `advanceReadiness()` method. + + If there is any setup required before routing begins, you can implement a + `ready()` method on your app that will be invoked immediately before routing + begins. + ``` + + @class Application + @namespace Ember + @extends Ember.Namespace +*/ + +var Application = Ember.Application = Ember.Namespace.extend(Ember.DeferredMixin, { + + /** + The root DOM element of the Application. This can be specified as an + element or a + [jQuery-compatible selector string](http://api.jquery.com/category/selectors/). + + This is the element that will be passed to the Application's, + `eventDispatcher`, which sets up the listeners for event delegation. Every + view in your application should be a child of the element you specify here. + + @property rootElement + @type DOMElement + @default 'body' + */ + rootElement: 'body', + + /** + The `Ember.EventDispatcher` responsible for delegating events to this + application's views. + + The event dispatcher is created by the application at initialization time + and sets up event listeners on the DOM element described by the + application's `rootElement` property. + + See the documentation for `Ember.EventDispatcher` for more information. + + @property eventDispatcher + @type Ember.EventDispatcher + @default null + */ + eventDispatcher: null, + + /** + The DOM events for which the event dispatcher should listen. + + By default, the application's `Ember.EventDispatcher` listens + for a set of standard DOM events, such as `mousedown` and + `keyup`, and delegates them to your application's `Ember.View` + instances. + + If you would like additional bubbling events to be delegated to your + views, set your `Ember.Application`'s `customEvents` property + to a hash containing the DOM event name as the key and the + corresponding view method name as the value. For example: + + ```javascript + App = Ember.Application.create({ + customEvents: { + // add support for the paste event + 'paste: "paste" + } + }); + ``` + + @property customEvents + @type Object + @default null + */ + customEvents: null, + + // Start off the number of deferrals at 1. This will be + // decremented by the Application's own `initialize` method. + _readinessDeferrals: 1, + + init: function() { + if (!this.$) { this.$ = Ember.$; } + this.__container__ = this.buildContainer(); + + this.Router = this.defaultRouter(); + + this._super(); + + this.scheduleInitialize(); + + Ember.libraries.registerCoreLibrary('Handlebars', Ember.Handlebars.VERSION); + Ember.libraries.registerCoreLibrary('jQuery', Ember.$().jquery); + + if ( Ember.LOG_VERSION ) { + Ember.LOG_VERSION = false; // we only need to see this once per Application#init + var maxNameLength = Math.max.apply(this, Ember.A(Ember.libraries).mapBy("name.length")); + + Ember.debug('-------------------------------'); + Ember.libraries.each(function(name, version) { + var spaces = new Array(maxNameLength - name.length + 1).join(" "); + Ember.debug([name, spaces, ' : ', version].join("")); + }); + Ember.debug('-------------------------------'); + } + }, + + /** + @private + + Build the container for the current application. + + Also register a default application view in case the application + itself does not. + + @method buildContainer + @return {Ember.Container} the configured container + */ + buildContainer: function() { + var container = this.__container__ = Application.buildContainer(this); + + return container; + }, + + /** + @private + + If the application has not opted out of routing and has not explicitly + defined a router, supply a default router for the application author + to configure. + + This allows application developers to do: + + ```javascript + var App = Ember.Application.create(); + + App.Router.map(function() { + this.resource('posts'); + }); + ``` + + @method defaultRouter + @return {Ember.Router} the default router + */ + + defaultRouter: function() { + if (this.Router === false) { return; } + var container = this.__container__; + + if (this.Router) { + container.unregister('router:main'); + container.register('router:main', this.Router); + } + + return container.lookupFactory('router:main'); + }, + + /** + @private + + Automatically initialize the application once the DOM has + become ready. + + The initialization itself is scheduled on the actions queue + which ensures that application loading finishes before + booting. + + If you are asynchronously loading code, you should call + `deferReadiness()` to defer booting, and then call + `advanceReadiness()` once all of your code has finished + loading. + + @method scheduleInitialize + */ + scheduleInitialize: function() { + var self = this; + + if (!this.$ || this.$.isReady) { + Ember.run.schedule('actions', self, '_initialize'); + } else { + this.$().ready(function() { + Ember.run(self, '_initialize'); + }); + } + }, + + /** + Use this to defer readiness until some condition is true. + + Example: + + ```javascript + App = Ember.Application.create(); + App.deferReadiness(); + + jQuery.getJSON("/auth-token", function(token) { + App.token = token; + App.advanceReadiness(); + }); + ``` + + This allows you to perform asynchronous setup logic and defer + booting your application until the setup has finished. + + However, if the setup requires a loading UI, it might be better + to use the router for this purpose. + + @method deferReadiness + */ + deferReadiness: function() { + Ember.assert("You must call deferReadiness on an instance of Ember.Application", this instanceof Ember.Application); + Ember.assert("You cannot defer readiness since the `ready()` hook has already been called.", this._readinessDeferrals > 0); + this._readinessDeferrals++; + }, + + /** + Call `advanceReadiness` after any asynchronous setup logic has completed. + Each call to `deferReadiness` must be matched by a call to `advanceReadiness` + or the application will never become ready and routing will not begin. + + @method advanceReadiness + @see {Ember.Application#deferReadiness} + */ + advanceReadiness: function() { + Ember.assert("You must call advanceReadiness on an instance of Ember.Application", this instanceof Ember.Application); + this._readinessDeferrals--; + + if (this._readinessDeferrals === 0) { + Ember.run.once(this, this.didBecomeReady); + } + }, + + /** + registers a factory for later injection + + Example: + + ```javascript + App = Ember.Application.create(); + + App.Person = Ember.Object.extend({}); + App.Orange = Ember.Object.extend({}); + App.Email = Ember.Object.extend({}); + App.Session = Ember.Object.create({}); + + App.register('model:user', App.Person, {singleton: false }); + App.register('fruit:favorite', App.Orange); + App.register('communication:main', App.Email, {singleton: false}); + App.register('session', App.Session, {instantiate: false}); + ``` + + @method register + @param fullName {String} type:name (e.g., 'model:user') + @param factory {Function} (e.g., App.Person) + @param options {String} (optional) + **/ + register: function() { + var container = this.__container__; + container.register.apply(container, arguments); + }, + /** + defines an injection or typeInjection + + Example: + + ```javascript + App.inject(, , ) + App.inject('model:user', 'email', 'model:email') + App.inject('model', 'source', 'source:main') + ``` + + @method inject + @param factoryNameOrType {String} + @param property {String} + @param injectionName {String} + **/ + inject: function() { + var container = this.__container__; + container.injection.apply(container, arguments); + }, + + /** + @private + @deprecated + + Calling initialize manually is not supported. + + Please see Ember.Application#advanceReadiness and + Ember.Application#deferReadiness. + + @method initialize + **/ + initialize: function() { + Ember.deprecate('Calling initialize manually is not supported. Please see Ember.Application#advanceReadiness and Ember.Application#deferReadiness'); + }, + /** + @private + + Initialize the application. This happens automatically. + + Run any initializers and run the application load hook. These hooks may + choose to defer readiness. For example, an authentication hook might want + to defer readiness until the auth token has been retrieved. + + @method _initialize + */ + _initialize: function() { + if (this.isDestroyed) { return; } + + // At this point, the App.Router must already be assigned + if (this.Router) { + var container = this.__container__; + container.unregister('router:main'); + container.register('router:main', this.Router); + } + + this.runInitializers(); + Ember.runLoadHooks('application', this); + + // At this point, any initializers or load hooks that would have wanted + // to defer readiness have fired. In general, advancing readiness here + // will proceed to didBecomeReady. + this.advanceReadiness(); + + return this; + }, + + /** + Reset the application. This is typically used only in tests. It cleans up + the application in the following order: + + 1. Deactivate existing routes + 2. Destroy all objects in the container + 3. Create a new application container + 4. Re-route to the existing url + + Typical Example: + + ```javascript + + var App; + + Ember.run(function() { + App = Ember.Application.create(); + }); + + module("acceptance test", { + setup: function() { + App.reset(); + } + }); + + test("first test", function() { + // App is freshly reset + }); + + test("first test", function() { + // App is again freshly reset + }); + ``` + + Advanced Example: + + Occasionally you may want to prevent the app from initializing during + setup. This could enable extra configuration, or enable asserting prior + to the app becoming ready. + + ```javascript + + var App; + + Ember.run(function() { + App = Ember.Application.create(); + }); + + module("acceptance test", { + setup: function() { + Ember.run(function() { + App.reset(); + App.deferReadiness(); + }); + } + }); + + test("first test", function() { + ok(true, 'something before app is initialized'); + + Ember.run(function() { + App.advanceReadiness(); + }); + ok(true, 'something after app is initialized'); + }); + ``` + + @method reset + **/ + reset: function() { + this._readinessDeferrals = 1; + + function handleReset() { + var router = this.__container__.lookup('router:main'); + router.reset(); + + Ember.run(this.__container__, 'destroy'); + + this.buildContainer(); + + Ember.run.schedule('actions', this, function() { + this._initialize(); + }); + } + + Ember.run.join(this, handleReset); + }, + + /** + @private + @method runInitializers + */ + runInitializers: function() { + var initializers = get(this.constructor, 'initializers'), + container = this.__container__, + graph = new Ember.DAG(), + namespace = this, + name, initializer; + + for (name in initializers) { + initializer = initializers[name]; + graph.addEdges(initializer.name, initializer.initialize, initializer.before, initializer.after); + } + + graph.topsort(function (vertex) { + var initializer = vertex.value; + Ember.assert("No application initializer named '"+vertex.name+"'", initializer); + initializer(container, namespace); + }); + }, + + /** + @private + @method didBecomeReady + */ + didBecomeReady: function() { + this.setupEventDispatcher(); + this.ready(); // user hook + this.startRouting(); + + if (!Ember.testing) { + // Eagerly name all classes that are already loaded + Ember.Namespace.processAll(); + Ember.BOOTED = true; + } + + this.resolve(this); + }, + + /** + @private + + Setup up the event dispatcher to receive events on the + application's `rootElement` with any registered + `customEvents`. + + @method setupEventDispatcher + */ + setupEventDispatcher: function() { + var customEvents = get(this, 'customEvents'), + rootElement = get(this, 'rootElement'), + dispatcher = this.__container__.lookup('event_dispatcher:main'); + + set(this, 'eventDispatcher', dispatcher); + dispatcher.setup(customEvents, rootElement); + }, + + /** + @private + + trigger a new call to `route` whenever the URL changes. + If the application has a router, use it to route to the current URL, and + + @method startRouting + @property router {Ember.Router} + */ + startRouting: function() { + var router = this.__container__.lookup('router:main'); + if (!router) { return; } + + router.startRouting(); + }, + + handleURL: function(url) { + var router = this.__container__.lookup('router:main'); + + router.handleURL(url); + }, + + /** + Called when the Application has become ready. + The call will be delayed until the DOM has become ready. + + @event ready + */ + ready: Ember.K, + + /** + @deprecated Use 'Resolver' instead + Set this to provide an alternate class to `Ember.DefaultResolver` + + + @property resolver + */ + resolver: null, + + /** + Set this to provide an alternate class to `Ember.DefaultResolver` + + @property resolver + */ + Resolver: null, + + willDestroy: function() { + Ember.BOOTED = false; + + this.__container__.destroy(); + }, + + initializer: function(options) { + this.constructor.initializer(options); + } +}); + +Ember.Application.reopenClass({ + initializers: {}, + initializer: function(initializer) { + // If this is the first initializer being added to a subclass, we are going to reopen the class + // to make sure we have a new `initializers` object, which extends from the parent class' using + // prototypal inheritance. Without this, attempting to add initializers to the subclass would + // pollute the parent class as well as other subclasses. + if (this.superclass.initializers !== undefined && this.superclass.initializers === this.initializers) { + this.reopenClass({ + initializers: Ember.create(this.initializers) + }); + } + + Ember.assert("The initializer '" + initializer.name + "' has already been registered", !this.initializers[initializer.name]); + Ember.assert("An initializer cannot be registered with both a before and an after", !(initializer.before && initializer.after)); + Ember.assert("An initializer cannot be registered without an initialize function", Ember.canInvoke(initializer, 'initialize')); + + this.initializers[initializer.name] = initializer; + }, + + /** + @private + + This creates a container with the default Ember naming conventions. + + It also configures the container: + + * registered views are created every time they are looked up (they are + not singletons) + * registered templates are not factories; the registered value is + returned directly. + * the router receives the application as its `namespace` property + * all controllers receive the router as their `target` and `controllers` + properties + * all controllers receive the application as their `namespace` property + * the application view receives the application controller as its + `controller` property + * the application view receives the application template as its + `defaultTemplate` property + + @method buildContainer + @static + @param {Ember.Application} namespace the application to build the + container for. + @return {Ember.Container} the built container + */ + buildContainer: function(namespace) { + var container = new Ember.Container(); + + Ember.Container.defaultContainer = new DeprecatedContainer(container); + + container.set = Ember.set; + container.resolver = resolverFor(namespace); + container.normalize = container.resolver.normalize; + container.describe = container.resolver.describe; + container.makeToString = container.resolver.makeToString; + + container.optionsForType('component', { singleton: false }); + container.optionsForType('view', { singleton: false }); + container.optionsForType('template', { instantiate: false }); + + + container.optionsForType('helper', { instantiate: false }); + + + container.register('application:main', namespace, { instantiate: false }); + + container.register('controller:basic', Ember.Controller, { instantiate: false }); + container.register('controller:object', Ember.ObjectController, { instantiate: false }); + container.register('controller:array', Ember.ArrayController, { instantiate: false }); + container.register('route:basic', Ember.Route, { instantiate: false }); + container.register('event_dispatcher:main', Ember.EventDispatcher); + + container.register('router:main', Ember.Router); + container.injection('router:main', 'namespace', 'application:main'); + + container.injection('controller', 'target', 'router:main'); + container.injection('controller', 'namespace', 'application:main'); + + container.injection('route', 'router', 'router:main'); + + return container; + } +}); + +/** + @private + + This function defines the default lookup rules for container lookups: + + * templates are looked up on `Ember.TEMPLATES` + * other names are looked up on the application after classifying the name. + For example, `controller:post` looks up `App.PostController` by default. + * if the default lookup fails, look for registered classes on the container + + This allows the application to register default injections in the container + that could be overridden by the normal naming convention. + + @method resolverFor + @param {Ember.Namespace} namespace the namespace to look for classes + @return {*} the resolved value for a given lookup +*/ +function resolverFor(namespace) { + if (namespace.get('resolver')) { + Ember.deprecate('Application.resolver is deprecated in favor of Application.Resolver', false); + } + + var ResolverClass = namespace.get('resolver') || namespace.get('Resolver') || Ember.DefaultResolver; + var resolver = ResolverClass.create({ + namespace: namespace + }); + + function resolve(fullName) { + return resolver.resolve(fullName); + } + + resolve.describe = function(fullName) { + return resolver.lookupDescription(fullName); + }; + + resolve.makeToString = function(factory, fullName) { + return resolver.makeToString(factory, fullName); + }; + + resolve.normalize = function(fullName) { + if (resolver.normalize) { + return resolver.normalize(fullName); + } else { + Ember.deprecate('The Resolver should now provide a \'normalize\' function', false); + return fullName; + } + }; + + return resolve; +} + +Ember.runLoadHooks('Ember.Application', Ember.Application); + +})(); + + + +(function() { + +})(); + + + +(function() { +/** +@module ember +@submodule ember-application +*/ + +var get = Ember.get, set = Ember.set; + +function verifyNeedsDependencies(controller, container, needs) { + var dependency, i, l; + + for (i=0, l=needs.length; i 0) { + Ember.assert(' `' + Ember.inspect(this) + ' specifies `needs`, but does not have a container. Please ensure this controller was instantiated with a container.', this.container); + + verifyNeedsDependencies(this, this.container, needs); + + // if needs then initialize controllers proxy + get(this, 'controllers'); + } + + this._super.apply(this, arguments); + }, + + /** + @method controllerFor + @see {Ember.Route#controllerFor} + @deprecated Use `needs` instead + */ + controllerFor: function(controllerName) { + Ember.deprecate("Controller#controllerFor is deprecated, please use Controller#needs instead"); + return Ember.controllerFor(get(this, 'container'), controllerName); + }, + + /** + Stores the instances of other controllers available from within + this controller. Any controller listed by name in the `needs` + property will be accessible by name through this property. + + ```javascript + App.CommentsController = Ember.ArrayController.extend({ + needs: ['post'], + postTitle: function(){ + var currentPost = this.get('controllers.post'); // instance of App.PostController + return currentPost.get('title'); + }.property('controllers.post.title') + }); + ``` + + @see {Ember.ControllerMixin#needs} + @property {Object} controllers + @default null + */ + controllers: Ember.computed(function() { + var controller = this; + + return { + needs: get(controller, 'needs'), + container: get(controller, 'container'), + unknownProperty: function(controllerName) { + var needs = this.needs, + dependency, i, l; + for (i=0, l=needs.length; i') + .css({ position: 'absolute', left: '-1000px', top: '-1000px' }) + .appendTo('body') + .on('click', handler) + .trigger('click') + .remove(); +} + +$(function() { + /* + Determine whether a checkbox checked using jQuery's "click" method will have + the correct value for its checked property. + + If we determine that the current jQuery version exhibits this behavior, + patch it to work correctly as in the commit for the actual fix: + https://github.com/jquery/jquery/commit/1fb2f92. + */ + testCheckboxClick(function() { + if (!this.checked && !$.event.special.click) { + $.event.special.click = { + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ($.nodeName( this, "input" ) && this.type === "checkbox" && this.click) { + this.click(); + return false; + } + } + }; + } + }); + + // Try again to verify that the patch took effect or blow up. + testCheckboxClick(function() { + Ember.warn("clicked checkboxes should be checked! the jQuery patch didn't work", this.checked); + }); +}); + +})(); + + + +(function() { +/** + @module ember + @submodule ember-testing +*/ + +var Test = Ember.Test; + +/** + The primary purpose of this class is to create hooks that can be implemented + by an adapter for various test frameworks. + + @class Adapter + @namespace Ember.Test +*/ +Test.Adapter = Ember.Object.extend({ + /** + This callback will be called whenever an async operation is about to start. + + Override this to call your framework's methods that handle async + operations. + + @public + @method asyncStart + */ + asyncStart: Ember.K, + + /** + This callback will be called whenever an async operation has completed. + + @public + @method asyncEnd + */ + asyncEnd: Ember.K, + + /** + Override this method with your testing framework's false assertion. + This function is called whenever an exception occurs causing the testing + promise to fail. + + QUnit example: + + ```javascript + exception: function(error) { + ok(false, error); + }; + ``` + + @public + @method exception + @param {String} error The exception to be raised. + */ + exception: function(error) { + setTimeout(function() { + throw error; + }); + } +}); + +/** + This class implements the methods defined by Ember.Test.Adapter for the + QUnit testing framework. + + @class QUnitAdapter + @namespace Ember.Test + @extends Ember.Test.Adapter +*/ +Test.QUnitAdapter = Test.Adapter.extend({ + asyncStart: function() { + stop(); + }, + asyncEnd: function() { + start(); + }, + exception: function(error) { + ok(false, Ember.inspect(error)); + } +}); + +})(); + + + +(function() { +/** +* @module ember +* @submodule ember-testing +*/ + +var get = Ember.get, + Test = Ember.Test, + helper = Test.registerHelper, + asyncHelper = Test.registerAsyncHelper, + countAsync = 0; + +Test.pendingAjaxRequests = 0; + +Test.onInjectHelpers(function() { + Ember.$(document).ajaxStart(function() { + Test.pendingAjaxRequests++; + }); + + Ember.$(document).ajaxStop(function() { + Ember.assert("An ajaxStop event which would cause the number of pending AJAX requests to be negative has been triggered. This is most likely caused by AJAX events that were started before calling `injectTestHelpers()`.", Test.pendingAjaxRequests !== 0); + Test.pendingAjaxRequests--; + }); +}); + + +function visit(app, url) { + app.__container__.lookup('router:main').location.setURL(url); + Ember.run(app, app.handleURL, url); + return wait(app); +} + +function click(app, selector, context) { + var $el = findWithAssert(app, selector, context); + Ember.run($el, 'mousedown'); + + if ($el.is(':input')) { + var type = $el.prop('type'); + if (type !== 'checkbox' && type !== 'radio' && type !== 'hidden') { + Ember.run($el, function(){ + // Firefox does not trigger the `focusin` event if the window + // does not have focus. If the document doesn't have focus just + // use trigger('focusin') instead. + if (!document.hasFocus || document.hasFocus()) { + this.focus(); + } else { + this.trigger('focusin'); + } + }); + } + } + + Ember.run($el, 'mouseup'); + Ember.run($el, 'click'); + + return wait(app); +} + +function keyEvent(app, selector, context, type, keyCode) { + var $el; + if (typeof keyCode === 'undefined') { + keyCode = type; + type = context; + context = null; + } + $el = findWithAssert(app, selector, context); + var event = Ember.$.Event(type, { keyCode: keyCode }); + Ember.run($el, 'trigger', event); + return wait(app); +} + +function fillIn(app, selector, context, text) { + var $el; + if (typeof text === 'undefined') { + text = context; + context = null; + } + $el = findWithAssert(app, selector, context); + Ember.run(function() { + $el.val(text).change(); + }); + return wait(app); +} + +function findWithAssert(app, selector, context) { + var $el = find(app, selector, context); + if ($el.length === 0) { + throw new Ember.Error("Element " + selector + " not found."); + } + return $el; +} + +function find(app, selector, context) { + var $el; + context = context || get(app, 'rootElement'); + $el = app.$(selector, context); + + return $el; +} + +function andThen(app, callback) { + return wait(app, callback(app)); +} + +function wait(app, value) { + return Test.promise(function(resolve) { + // If this is the first async promise, kick off the async test + if (++countAsync === 1) { + Test.adapter.asyncStart(); + } + + // Every 10ms, poll for the async thing to have finished + var watcher = setInterval(function() { + // 1. If the router is loading, keep polling + var routerIsLoading = app.__container__.lookup('router:main').router.isLoading; + if (routerIsLoading) { return; } + + // 2. If there are pending Ajax requests, keep polling + if (Test.pendingAjaxRequests) { return; } + + // 3. If there are scheduled timers or we are inside of a run loop, keep polling + if (Ember.run.hasScheduledTimers() || Ember.run.currentRunLoop) { return; } + // Stop polling + clearInterval(watcher); + + // If this is the last async promise, end the async test + if (--countAsync === 0) { + Test.adapter.asyncEnd(); + } + + // Synchronously resolve the promise + Ember.run(null, resolve, value); + }, 10); + }); + +} + + +/** +* Loads a route, sets up any controllers, and renders any templates associated +* with the route as though a real user had triggered the route change while +* using your app. +* +* Example: +* +* ``` +* visit('posts/index').then(function() { +* // assert something +* }); +* ``` +* +* @method visit +* @param {String} url the name of the route +* @return {RSVP.Promise} +*/ +asyncHelper('visit', visit); + +/** +* Clicks an element and triggers any actions triggered by the element's `click` +* event. +* +* Example: +* +* ``` +* click('.some-jQuery-selector').then(function() { +* // assert something +* }); +* ``` +* +* @method click +* @param {String} selector jQuery selector for finding element on the DOM +* @return {RSVP.Promise} +*/ +asyncHelper('click', click); + +/** +* Simulates a key event, e.g. `keypress`, `keydown`, `keyup` with the desired keyCode +* +* Example: +* +* ``` +* keyEvent('.some-jQuery-selector', 'keypress', 13).then(function() { +* // assert something +* }); +* ``` +* +* @method keyEvent +* @param {String} selector jQuery selector for finding element on the DOM +* @param {String} the type of key event, e.g. `keypress`, `keydown`, `keyup` +* @param {Number} the keyCode of the simulated key event +* @return {RSVP.Promise} +*/ +asyncHelper('keyEvent', keyEvent); + +/** +* Fills in an input element with some text. +* +* Example: +* +* ``` +* fillIn('#email', 'you@example.com').then(function() { +* // assert something +* }); +* ``` +* +* @method fillIn +* @param {String} selector jQuery selector finding an input element on the DOM +* to fill text with +* @param {String} text text to place inside the input element +* @return {RSVP.Promise} +*/ +asyncHelper('fillIn', fillIn); + +/** +* Finds an element in the context of the app's container element. A simple alias +* for `app.$(selector)`. +* +* Example: +* +* ``` +* var $el = find('.my-selector); +* ``` +* +* @method find +* @param {String} selector jQuery string selector for element lookup +* @return {Object} jQuery object representing the results of the query +*/ +helper('find', find); + +/** +* +* Like `find`, but throws an error if the element selector returns no results +* +* Example: +* +* ``` +* var $el = findWithAssert('.doesnt-exist'); // throws error +* ``` +* +* @method findWithAssert +* @param {String} selector jQuery selector string for finding an element within +* the DOM +* @return {Object} jQuery object representing the results of the query +* @throws {Error} throws error if jQuery object returned has a length of 0 +*/ +helper('findWithAssert', findWithAssert); + +/** + Causes the run loop to process any pending events. This is used to ensure that + any async operations from other helpers (or your assertions) have been processed. + + This is most often used as the return value for the helper functions (see 'click', + 'fillIn','visit',etc). + + Example: + + ``` + Ember.Test.registerAsyncHelper('loginUser', function(app, username, password) { + visit('secured/path/here') + .fillIn('#username', username) + .fillIn('#password', username) + .click('.submit') + + return wait(); + }); + + @method wait + @param {Object} value The value to be returned. + @return {RSVP.Promise} + ``` +*/ +asyncHelper('wait', wait); +asyncHelper('andThen', andThen); + +})(); + + + +(function() { +/** + Ember Testing + + @module ember + @submodule ember-testing + @requires ember-application +*/ + +})(); + +(function() { +/** +Ember + +@module ember +*/ + +function throwWithMessage(msg) { + return function() { + throw new Ember.Error(msg); + }; +} + +function generateRemovedClass(className) { + var msg = " has been moved into a plugin: https://github.com/emberjs/ember-states"; + + return { + extend: throwWithMessage(className + msg), + create: throwWithMessage(className + msg) + }; +} + +Ember.StateManager = generateRemovedClass("Ember.StateManager"); + +/** + This was exported to ember-states plugin for v 1.0.0 release. See: https://github.com/emberjs/ember-states + + @class StateManager + @namespace Ember +*/ + +Ember.State = generateRemovedClass("Ember.State"); + +/** + This was exported to ember-states plugin for v 1.0.0 release. See: https://github.com/emberjs/ember-states + + @class State + @namespace Ember +*/ + +})(); + + +exports.precompile = Ember.Handlebars.precompile; +exports.EmberHandlebars = Ember.Handlebars; +exports.LoadedEmber = Ember; +})(); diff --git a/bower_components/emblem/test/resources/browser/jquery-1.9.1.js b/bower_components/emblem/test/resources/browser/jquery-1.9.1.js new file mode 100644 index 0000000..86a3305 --- /dev/null +++ b/bower_components/emblem/test/resources/browser/jquery-1.9.1.js @@ -0,0 +1,9597 @@ +/*! + * jQuery JavaScript Library v1.9.1 + * http://jquery.com/ + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * + * Copyright 2005, 2012 jQuery Foundation, Inc. and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2013-2-4 + */ +(function( window, undefined ) { + +// Can't do this because several apps including ASP.NET trace +// the stack via arguments.caller.callee and Firefox dies if +// you try to trace through "use strict" call chains. (#13335) +// Support: Firefox 18+ +//"use strict"; +var + // The deferred used on DOM ready + readyList, + + // A central reference to the root jQuery(document) + rootjQuery, + + // Support: IE<9 + // For `typeof node.method` instead of `node.method !== undefined` + core_strundefined = typeof undefined, + + // Use the correct document accordingly with window argument (sandbox) + document = window.document, + location = window.location, + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$, + + // [[Class]] -> type pairs + class2type = {}, + + // List of deleted data cache ids, so we can reuse them + core_deletedIds = [], + + core_version = "1.9.1", + + // Save a reference to some core methods + core_concat = core_deletedIds.concat, + core_push = core_deletedIds.push, + core_slice = core_deletedIds.slice, + core_indexOf = core_deletedIds.indexOf, + core_toString = class2type.toString, + core_hasOwn = class2type.hasOwnProperty, + core_trim = core_version.trim, + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context, rootjQuery ); + }, + + // Used for matching numbers + core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source, + + // Used for splitting on whitespace + core_rnotwhite = /\S+/g, + + // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE) + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + rquickExpr = /^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, + + // JSON RegExp + rvalidchars = /^[\],:{}\s]*$/, + rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, + rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, + rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([\da-z])/gi, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }, + + // The ready event handler + completed = function( event ) { + + // readyState === "complete" is good enough for us to call the dom ready in oldIE + if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) { + detach(); + jQuery.ready(); + } + }, + // Clean-up method for dom ready events + detach = function() { + if ( document.addEventListener ) { + document.removeEventListener( "DOMContentLoaded", completed, false ); + window.removeEventListener( "load", completed, false ); + + } else { + document.detachEvent( "onreadystatechange", completed ); + window.detachEvent( "onload", completed ); + } + }; + +jQuery.fn = jQuery.prototype = { + // The current version of jQuery being used + jquery: core_version, + + constructor: jQuery, + init: function( selector, context, rootjQuery ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + + // scripts is true for back-compat + jQuery.merge( this, jQuery.parseHTML( + match[1], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[2] ); + + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || rootjQuery ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return core_slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this[ this.length + num ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + ret.context = this.context; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Add the callback + jQuery.ready.promise().done( fn ); + + return this; + }, + + slice: function() { + return this.pushStack( core_slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: core_push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + var src, copyIsArray, copy, name, options, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + noConflict: function( deep ) { + if ( window.$ === jQuery ) { + window.$ = _$; + } + + if ( deep && window.jQuery === jQuery ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.trigger ) { + jQuery( document ).trigger("ready").off("ready"); + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray || function( obj ) { + return jQuery.type(obj) === "array"; + }, + + isWindow: function( obj ) { + return obj != null && obj == obj.window; + }, + + isNumeric: function( obj ) { + return !isNaN( parseFloat(obj) ) && isFinite( obj ); + }, + + type: function( obj ) { + if ( obj == null ) { + return String( obj ); + } + return typeof obj === "object" || typeof obj === "function" ? + class2type[ core_toString.call(obj) ] || "object" : + typeof obj; + }, + + isPlainObject: function( obj ) { + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + try { + // Not own constructor property must be Object + if ( obj.constructor && + !core_hasOwn.call(obj, "constructor") && + !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + } catch ( e ) { + // IE8,9 Will throw exceptions on certain host objects #9897 + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || core_hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + var name; + for ( name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw new Error( msg ); + }, + + // data: string of html + // context (optional): If specified, the fragment will be created in this context, defaults to document + // keepScripts (optional): If true, will include scripts passed in the html string + parseHTML: function( data, context, keepScripts ) { + if ( !data || typeof data !== "string" ) { + return null; + } + if ( typeof context === "boolean" ) { + keepScripts = context; + context = false; + } + context = context || document; + + var parsed = rsingleTag.exec( data ), + scripts = !keepScripts && []; + + // Single tag + if ( parsed ) { + return [ context.createElement( parsed[1] ) ]; + } + + parsed = jQuery.buildFragment( [ data ], context, scripts ); + if ( scripts ) { + jQuery( scripts ).remove(); + } + return jQuery.merge( [], parsed.childNodes ); + }, + + parseJSON: function( data ) { + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( data ); + } + + if ( data === null ) { + return data; + } + + if ( typeof data === "string" ) { + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + if ( data ) { + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { + + return ( new Function( "return " + data ) )(); + } + } + } + + jQuery.error( "Invalid JSON: " + data ); + }, + + // Cross-browser xml parsing + parseXML: function( data ) { + var xml, tmp; + if ( !data || typeof data !== "string" ) { + return null; + } + try { + if ( window.DOMParser ) { // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString( data , "text/xml" ); + } else { // IE + xml = new ActiveXObject( "Microsoft.XMLDOM" ); + xml.async = "false"; + xml.loadXML( data ); + } + } catch( e ) { + xml = undefined; + } + if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; + }, + + noop: function() {}, + + // Evaluates a script in a global context + // Workarounds based on findings by Jim Driscoll + // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context + globalEval: function( data ) { + if ( data && jQuery.trim( data ) ) { + // We use execScript on Internet Explorer + // We use an anonymous function so that context is window + // rather than jQuery in Firefox + ( window.execScript || function( data ) { + window[ "eval" ].call( window, data ); + } )( data ); + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + }, + + // args is for internal usage only + each: function( obj, callback, args ) { + var value, + i = 0, + length = obj.length, + isArray = isArraylike( obj ); + + if ( args ) { + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback.apply( obj[ i ], args ); + + if ( value === false ) { + break; + } + } + } else { + for ( i in obj ) { + value = callback.apply( obj[ i ], args ); + + if ( value === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback.call( obj[ i ], i, obj[ i ] ); + + if ( value === false ) { + break; + } + } + } else { + for ( i in obj ) { + value = callback.call( obj[ i ], i, obj[ i ] ); + + if ( value === false ) { + break; + } + } + } + } + + return obj; + }, + + // Use native String.trim function wherever possible + trim: core_trim && !core_trim.call("\uFEFF\xA0") ? + function( text ) { + return text == null ? + "" : + core_trim.call( text ); + } : + + // Otherwise use our own trimming functionality + function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArraylike( Object(arr) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + core_push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + var len; + + if ( arr ) { + if ( core_indexOf ) { + return core_indexOf.call( arr, elem, i ); + } + + len = arr.length; + i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; + + for ( ; i < len; i++ ) { + // Skip accessing in sparse arrays + if ( i in arr && arr[ i ] === elem ) { + return i; + } + } + } + + return -1; + }, + + merge: function( first, second ) { + var l = second.length, + i = first.length, + j = 0; + + if ( typeof l === "number" ) { + for ( ; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var retVal, + ret = [], + i = 0, + length = elems.length; + inv = !!inv; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + retVal = !!callback( elems[ i ], i ); + if ( inv !== retVal ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, + i = 0, + length = elems.length, + isArray = isArraylike( elems ), + ret = []; + + // Go through the array, translating each of the items to their + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + } + + // Flatten any nested arrays + return core_concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var args, proxy, tmp; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = core_slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + // Multifunctional method to get and set values of a collection + // The value/s can optionally be executed if it's a function + access: function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + length = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < length; i++ ) { + fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); + } + } + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + length ? fn( elems[0], key ) : emptyGet; + }, + + now: function() { + return ( new Date() ).getTime(); + } +}); + +jQuery.ready.promise = function( obj ) { + if ( !readyList ) { + + readyList = jQuery.Deferred(); + + // Catch cases where $(document).ready() is called after the browser event has already occurred. + // we once tried to use readyState "interactive" here, but it caused issues like the one + // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + setTimeout( jQuery.ready ); + + // Standards-based browsers support DOMContentLoaded + } else if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed, false ); + + // If IE event model is used + } else { + // Ensure firing before onload, maybe late but safe also for iframes + document.attachEvent( "onreadystatechange", completed ); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", completed ); + + // If IE and not a frame + // continually check to see if the document is ready + var top = false; + + try { + top = window.frameElement == null && document.documentElement; + } catch(e) {} + + if ( top && top.doScroll ) { + (function doScrollCheck() { + if ( !jQuery.isReady ) { + + try { + // Use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + top.doScroll("left"); + } catch(e) { + return setTimeout( doScrollCheck, 50 ); + } + + // detach all dom ready events + detach(); + + // and execute any waiting functions + jQuery.ready(); + } + })(); + } + } + } + return readyList.promise( obj ); +}; + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +function isArraylike( obj ) { + var length = obj.length, + type = jQuery.type( obj ); + + if ( jQuery.isWindow( obj ) ) { + return false; + } + + if ( obj.nodeType === 1 && length ) { + return true; + } + + return type === "array" || type !== "function" && + ( length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj ); +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); +// String to Object options format cache +var optionsCache = {}; + +// Convert String-formatted options into Object-formatted ones and store in cache +function createOptions( options ) { + var object = optionsCache[ options ] = {}; + jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) { + object[ flag ] = true; + }); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + ( optionsCache[ options ] || createOptions( options ) ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list was already fired + fired, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // First callback to fire (used internally by add and fireWith) + firingStart, + // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = !options.once && [], + // Fire callbacks + fire = function( data ) { + memory = options.memory && data; + fired = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + firing = true; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { + memory = false; // To prevent further calls using add + break; + } + } + firing = false; + if ( list ) { + if ( stack ) { + if ( stack.length ) { + fire( stack.shift() ); + } + } else if ( memory ) { + list = []; + } else { + self.disable(); + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + // First, we save the current length + var start = list.length; + (function add( args ) { + jQuery.each( args, function( _, arg ) { + var type = jQuery.type( arg ); + if ( type === "function" ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && type !== "string" ) { + // Inspect recursively + add( arg ); + } + }); + })( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away + } else if ( memory ) { + firingStart = start; + fire( memory ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + jQuery.each( arguments, function( _, arg ) { + var index; + while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + // Handle firing indexes + if ( firing ) { + if ( index <= firingLength ) { + firingLength--; + } + if ( index <= firingIndex ) { + firingIndex--; + } + } + } + }); + } + return this; + }, + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); + }, + // Remove all callbacks from the list + empty: function() { + list = []; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + if ( list && ( !fired || stack ) ) { + if ( firing ) { + stack.push( args ); + } else { + fire( args ); + } + } + return this; + }, + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; +jQuery.extend({ + + Deferred: function( func ) { + var tuples = [ + // action, add listener, listener list, final state + [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], + [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], + [ "notify", "progress", jQuery.Callbacks("memory") ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + then: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + return jQuery.Deferred(function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + var action = tuple[ 0 ], + fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; + // deferred[ done | fail | progress ] for forwarding actions to newDefer + deferred[ tuple[1] ](function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .done( newDefer.resolve ) + .fail( newDefer.reject ) + .progress( newDefer.notify ); + } else { + newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); + } + }); + }); + fns = null; + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Keep pipe for back-compat + promise.pipe = promise.then; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 3 ]; + + // promise[ done | fail | progress ] = list.add + promise[ tuple[1] ] = list.add; + + // Handle state + if ( stateString ) { + list.add(function() { + // state = [ resolved | rejected ] + state = stateString; + + // [ reject_list | resolve_list ].disable; progress_list.lock + }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); + } + + // deferred[ resolve | reject | notify ] + deferred[ tuple[0] ] = function() { + deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); + return this; + }; + deferred[ tuple[0] + "With" ] = list.fireWith; + }); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( subordinate /* , ..., subordinateN */ ) { + var i = 0, + resolveValues = core_slice.call( arguments ), + length = resolveValues.length, + + // the count of uncompleted subordinates + remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, + + // the master Deferred. If resolveValues consist of only a single Deferred, just use that. + deferred = remaining === 1 ? subordinate : jQuery.Deferred(), + + // Update function for both resolve and progress values + updateFunc = function( i, contexts, values ) { + return function( value ) { + contexts[ i ] = this; + values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; + if( values === progressValues ) { + deferred.notifyWith( contexts, values ); + } else if ( !( --remaining ) ) { + deferred.resolveWith( contexts, values ); + } + }; + }, + + progressValues, progressContexts, resolveContexts; + + // add listeners to Deferred subordinates; treat others as resolved + if ( length > 1 ) { + progressValues = new Array( length ); + progressContexts = new Array( length ); + resolveContexts = new Array( length ); + for ( ; i < length; i++ ) { + if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { + resolveValues[ i ].promise() + .done( updateFunc( i, resolveContexts, resolveValues ) ) + .fail( deferred.reject ) + .progress( updateFunc( i, progressContexts, progressValues ) ); + } else { + --remaining; + } + } + } + + // if we're not waiting on anything, resolve the master + if ( !remaining ) { + deferred.resolveWith( resolveContexts, resolveValues ); + } + + return deferred.promise(); + } +}); +jQuery.support = (function() { + + var support, all, a, + input, select, fragment, + opt, eventName, isSupported, i, + div = document.createElement("div"); + + // Setup + div.setAttribute( "className", "t" ); + div.innerHTML = "
    a"; + + // Support tests won't run in some limited or non-browser environments + all = div.getElementsByTagName("*"); + a = div.getElementsByTagName("a")[ 0 ]; + if ( !all || !a || !all.length ) { + return {}; + } + + // First batch of tests + select = document.createElement("select"); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName("input")[ 0 ]; + + a.style.cssText = "top:1px;float:left;opacity:.5"; + support = { + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) + getSetAttribute: div.className !== "t", + + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: div.firstChild.nodeType === 3, + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName("tbody").length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName("link").length, + + // Get the style information from getAttribute + // (IE uses .cssText instead) + style: /top/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: a.getAttribute("href") === "/a", + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.5/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere) + checkOn: !!input.value, + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: opt.selected, + + // Tests for enctype support on a form (#6743) + enctype: !!document.createElement("form").enctype, + + // Makes sure cloning an html5 element does not cause problems + // Where outerHTML is undefined, this still works + html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", + + // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode + boxModel: document.compatMode === "CSS1Compat", + + // Will be defined later + deleteExpando: true, + noCloneEvent: true, + inlineBlockNeedsLayout: false, + shrinkWrapBlocks: false, + reliableMarginRight: true, + boxSizingReliable: true, + pixelPosition: false + }; + + // Make sure checked status is properly cloned + input.checked = true; + support.noCloneChecked = input.cloneNode( true ).checked; + + // Make sure that the options inside disabled selects aren't marked as disabled + // (WebKit marks them as disabled) + select.disabled = true; + support.optDisabled = !opt.disabled; + + // Support: IE<9 + try { + delete div.test; + } catch( e ) { + support.deleteExpando = false; + } + + // Check if we can trust getAttribute("value") + input = document.createElement("input"); + input.setAttribute( "value", "" ); + support.input = input.getAttribute( "value" ) === ""; + + // Check if an input maintains its value after becoming a radio + input.value = "t"; + input.setAttribute( "type", "radio" ); + support.radioValue = input.value === "t"; + + // #11217 - WebKit loses check when the name is after the checked attribute + input.setAttribute( "checked", "t" ); + input.setAttribute( "name", "t" ); + + fragment = document.createDocumentFragment(); + fragment.appendChild( input ); + + // Check if a disconnected checkbox will retain its checked + // value of true after appended to the DOM (IE6/7) + support.appendChecked = input.checked; + + // WebKit doesn't clone checked state correctly in fragments + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE<9 + // Opera does not clone events (and typeof div.attachEvent === undefined). + // IE9-10 clones events bound via attachEvent, but they don't trigger with .click() + if ( div.attachEvent ) { + div.attachEvent( "onclick", function() { + support.noCloneEvent = false; + }); + + div.cloneNode( true ).click(); + } + + // Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event) + // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP), test/csp.php + for ( i in { submit: true, change: true, focusin: true }) { + div.setAttribute( eventName = "on" + i, "t" ); + + support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false; + } + + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + // Run tests that need a body at doc ready + jQuery(function() { + var container, marginDiv, tds, + divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;", + body = document.getElementsByTagName("body")[0]; + + if ( !body ) { + // Return for frameset docs that don't have a body + return; + } + + container = document.createElement("div"); + container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px"; + + body.appendChild( container ).appendChild( div ); + + // Support: IE8 + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + div.innerHTML = "
    t
    "; + tds = div.getElementsByTagName("td"); + tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none"; + isSupported = ( tds[ 0 ].offsetHeight === 0 ); + + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; + + // Support: IE8 + // Check if empty table cells still have offsetWidth/Height + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + + // Check box-sizing and margin behavior + div.innerHTML = ""; + div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;"; + support.boxSizing = ( div.offsetWidth === 4 ); + support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 ); + + // Use window.getComputedStyle because jsdom on node.js will break without it. + if ( window.getComputedStyle ) { + support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; + support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; + + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. (#3333) + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + marginDiv = div.appendChild( document.createElement("div") ); + marginDiv.style.cssText = div.style.cssText = divReset; + marginDiv.style.marginRight = marginDiv.style.width = "0"; + div.style.width = "1px"; + + support.reliableMarginRight = + !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); + } + + if ( typeof div.style.zoom !== core_strundefined ) { + // Support: IE<8 + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + div.innerHTML = ""; + div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1"; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); + + // Support: IE6 + // Check if elements with layout shrink-wrap their children + div.style.display = "block"; + div.innerHTML = "
    "; + div.firstChild.style.width = "5px"; + support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); + + if ( support.inlineBlockNeedsLayout ) { + // Prevent IE 6 from affecting layout for positioned elements #11048 + // Prevent IE from shrinking the body in IE 7 mode #12869 + // Support: IE<8 + body.style.zoom = 1; + } + } + + body.removeChild( container ); + + // Null elements to avoid leaks in IE + container = div = tds = marginDiv = null; + }); + + // Null elements to avoid leaks in IE + all = select = fragment = opt = a = input = null; + + return support; +})(); + +var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/, + rmultiDash = /([A-Z])/g; + +function internalData( elem, name, data, pvt /* Internal Use Only */ ){ + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var thisCache, ret, + internalKey = jQuery.expando, + getByName = typeof name === "string", + + // We have to handle DOM nodes and JS objects differently because IE6-7 + // can't GC object references properly across the DOM-JS boundary + isNode = elem.nodeType, + + // Only DOM nodes need the global jQuery cache; JS object data is + // attached directly to the object so GC can occur automatically + cache = isNode ? jQuery.cache : elem, + + // Only defining an ID for JS objects if its cache already exists allows + // the code to shortcut on the same path as a DOM node with no cache + id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; + + // Avoid doing any more work than we need to when trying to get data on an + // object that has no data at all + if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) { + return; + } + + if ( !id ) { + // Only DOM nodes need a new unique ID for each element since their data + // ends up in the global cache + if ( isNode ) { + elem[ internalKey ] = id = core_deletedIds.pop() || jQuery.guid++; + } else { + id = internalKey; + } + } + + if ( !cache[ id ] ) { + cache[ id ] = {}; + + // Avoids exposing jQuery metadata on plain JS objects when the object + // is serialized using JSON.stringify + if ( !isNode ) { + cache[ id ].toJSON = jQuery.noop; + } + } + + // An object can be passed to jQuery.data instead of a key/value pair; this gets + // shallow copied over onto the existing cache + if ( typeof name === "object" || typeof name === "function" ) { + if ( pvt ) { + cache[ id ] = jQuery.extend( cache[ id ], name ); + } else { + cache[ id ].data = jQuery.extend( cache[ id ].data, name ); + } + } + + thisCache = cache[ id ]; + + // jQuery data() is stored in a separate object inside the object's internal data + // cache in order to avoid key collisions between internal data and user-defined + // data. + if ( !pvt ) { + if ( !thisCache.data ) { + thisCache.data = {}; + } + + thisCache = thisCache.data; + } + + if ( data !== undefined ) { + thisCache[ jQuery.camelCase( name ) ] = data; + } + + // Check for both converted-to-camel and non-converted data property names + // If a data property was specified + if ( getByName ) { + + // First Try to find as-is property data + ret = thisCache[ name ]; + + // Test for null|undefined property data + if ( ret == null ) { + + // Try to find the camelCased property + ret = thisCache[ jQuery.camelCase( name ) ]; + } + } else { + ret = thisCache; + } + + return ret; +} + +function internalRemoveData( elem, name, pvt ) { + if ( !jQuery.acceptData( elem ) ) { + return; + } + + var i, l, thisCache, + isNode = elem.nodeType, + + // See jQuery.data for more information + cache = isNode ? jQuery.cache : elem, + id = isNode ? elem[ jQuery.expando ] : jQuery.expando; + + // If there is already no cache entry for this object, there is no + // purpose in continuing + if ( !cache[ id ] ) { + return; + } + + if ( name ) { + + thisCache = pvt ? cache[ id ] : cache[ id ].data; + + if ( thisCache ) { + + // Support array or space separated string names for data keys + if ( !jQuery.isArray( name ) ) { + + // try the string as a key before any manipulation + if ( name in thisCache ) { + name = [ name ]; + } else { + + // split the camel cased version by spaces unless a key with the spaces exists + name = jQuery.camelCase( name ); + if ( name in thisCache ) { + name = [ name ]; + } else { + name = name.split(" "); + } + } + } else { + // If "name" is an array of keys... + // When data is initially created, via ("key", "val") signature, + // keys will be converted to camelCase. + // Since there is no way to tell _how_ a key was added, remove + // both plain key and camelCase key. #12786 + // This will only penalize the array argument path. + name = name.concat( jQuery.map( name, jQuery.camelCase ) ); + } + + for ( i = 0, l = name.length; i < l; i++ ) { + delete thisCache[ name[i] ]; + } + + // If there is no data left in the cache, we want to continue + // and let the cache object itself get destroyed + if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { + return; + } + } + } + + // See jQuery.data for more information + if ( !pvt ) { + delete cache[ id ].data; + + // Don't destroy the parent cache unless the internal data object + // had been the only thing left in it + if ( !isEmptyDataObject( cache[ id ] ) ) { + return; + } + } + + // Destroy the cache + if ( isNode ) { + jQuery.cleanData( [ elem ], true ); + + // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) + } else if ( jQuery.support.deleteExpando || cache != cache.window ) { + delete cache[ id ]; + + // When all else fails, null + } else { + cache[ id ] = null; + } +} + +jQuery.extend({ + cache: {}, + + // Unique for each copy of jQuery on the page + // Non-digits removed to match rinlinejQuery + expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ), + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + // Ban all objects except for Flash (which handle expandos) + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + + hasData: function( elem ) { + elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; + return !!elem && !isEmptyDataObject( elem ); + }, + + data: function( elem, name, data ) { + return internalData( elem, name, data ); + }, + + removeData: function( elem, name ) { + return internalRemoveData( elem, name ); + }, + + // For internal use only. + _data: function( elem, name, data ) { + return internalData( elem, name, data, true ); + }, + + _removeData: function( elem, name ) { + return internalRemoveData( elem, name, true ); + }, + + // A method for determining if a DOM node can handle the data expando + acceptData: function( elem ) { + // Do not set data on non-element because it will not be cleared (#8335). + if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) { + return false; + } + + var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ]; + + // nodes accept data unless otherwise specified; rejection can be conditional + return !noData || noData !== true && elem.getAttribute("classid") === noData; + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var attrs, name, + elem = this[0], + i = 0, + data = null; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = jQuery.data( elem ); + + if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { + attrs = elem.attributes; + for ( ; i < attrs.length; i++ ) { + name = attrs[i].name; + + if ( !name.indexOf( "data-" ) ) { + name = jQuery.camelCase( name.slice(5) ); + + dataAttr( elem, name, data[ name ] ); + } + } + jQuery._data( elem, "parsedAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + return jQuery.access( this, function( value ) { + + if ( value === undefined ) { + // Try to fetch any internally stored data first + return elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null; + } + + this.each(function() { + jQuery.data( this, key, value ); + }); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); + +function dataAttr( elem, key, data ) { + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + + var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + // Only convert to a number if it doesn't change the string + +data + "" === data ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + jQuery.data( elem, key, data ); + + } else { + data = undefined; + } + } + + return data; +} + +// checks a cache object for emptiness +function isEmptyDataObject( obj ) { + var name; + for ( name in obj ) { + + // if the public data object is empty, the private is still empty + if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { + continue; + } + if ( name !== "toJSON" ) { + return false; + } + } + + return true; +} +jQuery.extend({ + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = jQuery._data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || jQuery.isArray(data) ) { + queue = jQuery._data( elem, type, jQuery.makeArray(data) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + hooks.cur = fn; + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // not intended for public consumption - generates a queueHooks object, or returns the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return jQuery._data( elem, key ) || jQuery._data( elem, key, { + empty: jQuery.Callbacks("once memory").add(function() { + jQuery._removeData( elem, type + "queue" ); + jQuery._removeData( elem, key ); + }) + }); + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[0], type ); + } + + return data === undefined ? + this : + this.each(function() { + var queue = jQuery.queue( this, type, data ); + + // ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = setTimeout( next, time ); + hooks.stop = function() { + clearTimeout( timeout ); + }; + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while( i-- ) { + tmp = jQuery._data( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +}); +var nodeHook, boolHook, + rclass = /[\t\r\n]/g, + rreturn = /\r/g, + rfocusable = /^(?:input|select|textarea|button|object)$/i, + rclickable = /^(?:a|area)$/i, + rboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i, + ruseDefault = /^(?:checked|selected)$/i, + getSetAttribute = jQuery.support.getSetAttribute, + getSetInput = jQuery.support.input; + +jQuery.fn.extend({ + attr: function( name, value ) { + return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each(function() { + jQuery.removeAttr( this, name ); + }); + }, + + prop: function( name, value ) { + return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + name = jQuery.propFix[ name ] || name; + return this.each(function() { + // try/catch handles cases where IE balks (such as removing a property on window) + try { + this[ name ] = undefined; + delete this[ name ]; + } catch( e ) {} + }); + }, + + addClass: function( value ) { + var classes, elem, cur, clazz, j, + i = 0, + len = this.length, + proceed = typeof value === "string" && value; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).addClass( value.call( this, j, this.className ) ); + }); + } + + if ( proceed ) { + // The disjunction here is for better compressibility (see removeClass) + classes = ( value || "" ).match( core_rnotwhite ) || []; + + for ( ; i < len; i++ ) { + elem = this[ i ]; + cur = elem.nodeType === 1 && ( elem.className ? + ( " " + elem.className + " " ).replace( rclass, " " ) : + " " + ); + + if ( cur ) { + j = 0; + while ( (clazz = classes[j++]) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + elem.className = jQuery.trim( cur ); + + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, clazz, j, + i = 0, + len = this.length, + proceed = arguments.length === 0 || typeof value === "string" && value; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( j ) { + jQuery( this ).removeClass( value.call( this, j, this.className ) ); + }); + } + if ( proceed ) { + classes = ( value || "" ).match( core_rnotwhite ) || []; + + for ( ; i < len; i++ ) { + elem = this[ i ]; + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( elem.className ? + ( " " + elem.className + " " ).replace( rclass, " " ) : + "" + ); + + if ( cur ) { + j = 0; + while ( (clazz = classes[j++]) ) { + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) >= 0 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + elem.className = value ? jQuery.trim( cur ) : ""; + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function( i ) { + jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, + i = 0, + self = jQuery( this ), + state = stateVal, + classNames = value.match( core_rnotwhite ) || []; + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space separated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + // Toggle whole class name + } else if ( type === core_strundefined || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery._data( this, "__className__", this.className ); + } + + // If the element has a class name or if we're passed "false", + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " ", + i = 0, + l = this.length; + for ( ; i < l; i++ ) { + if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + var ret, hooks, isFunction, + elem = this[0]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { + return ret; + } + + ret = elem.value; + + return typeof ret === "string" ? + // handle most common string cases + ret.replace(rreturn, "") : + // handle cases where value is null/undef or number + ret == null ? "" : ret; + } + + return; + } + + isFunction = jQuery.isFunction( value ); + + return this.each(function( i ) { + var val, + self = jQuery(this); + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call( this, i, self.val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + } else if ( typeof val === "number" ) { + val += ""; + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { + return value == null ? "" : value + ""; + }); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + valHooks: { + option: { + get: function( elem ) { + // attributes.value is undefined in Blackberry 4.7 but + // uses .value. See #6932 + var val = elem.attributes.value; + return !val || val.specified ? elem.value : elem.text; + } + }, + select: { + get: function( elem ) { + var value, option, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one" || index < 0, + values = one ? null : [], + max = one ? index + 1 : options.length, + i = index < 0 ? + max : + one ? index : 0; + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // oldIE doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + // Don't return options that are disabled or in a disabled optgroup + ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) && + ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var values = jQuery.makeArray( value ); + + jQuery(elem).find("option").each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + elem.selectedIndex = -1; + } + return values; + } + } + }, + + attr: function( elem, name, value ) { + var hooks, notxml, ret, + nType = elem.nodeType; + + // don't get/set attributes on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === core_strundefined ) { + return jQuery.prop( elem, name, value ); + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + // All attributes are lowercase + // Grab necessary hook if one is defined + if ( notxml ) { + name = name.toLowerCase(); + hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); + } + + if ( value !== undefined ) { + + if ( value === null ) { + jQuery.removeAttr( elem, name ); + + } else if ( hooks && notxml && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + elem.setAttribute( name, value + "" ); + return value; + } + + } else if ( hooks && notxml && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + + // In IE9+, Flash objects don't have .getAttribute (#12945) + // Support: IE9+ + if ( typeof elem.getAttribute !== core_strundefined ) { + ret = elem.getAttribute( name ); + } + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? + undefined : + ret; + } + }, + + removeAttr: function( elem, value ) { + var name, propName, + i = 0, + attrNames = value && value.match( core_rnotwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( (name = attrNames[i++]) ) { + propName = jQuery.propFix[ name ] || name; + + // Boolean attributes get special treatment (#10870) + if ( rboolean.test( name ) ) { + // Set corresponding property to false for boolean attributes + // Also clear defaultChecked/defaultSelected (if appropriate) for IE<8 + if ( !getSetAttribute && ruseDefault.test( name ) ) { + elem[ jQuery.camelCase( "default-" + name ) ] = + elem[ propName ] = false; + } else { + elem[ propName ] = false; + } + + // See #9699 for explanation of this approach (setting first, then removal) + } else { + jQuery.attr( elem, name, "" ); + } + + elem.removeAttribute( getSetAttribute ? name : propName ); + } + } + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { + // Setting the type on a radio button after the value resets the value in IE6-9 + // Reset value to default in case type is set after value during creation + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + propFix: { + tabindex: "tabIndex", + readonly: "readOnly", + "for": "htmlFor", + "class": "className", + maxlength: "maxLength", + cellspacing: "cellSpacing", + cellpadding: "cellPadding", + rowspan: "rowSpan", + colspan: "colSpan", + usemap: "useMap", + frameborder: "frameBorder", + contenteditable: "contentEditable" + }, + + prop: function( elem, name, value ) { + var ret, hooks, notxml, + nType = elem.nodeType; + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + + if ( notxml ) { + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { + return ret; + + } else { + return ( elem[ name ] = value ); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + return ret; + + } else { + return elem[ name ]; + } + } + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + var attributeNode = elem.getAttributeNode("tabindex"); + + return attributeNode && attributeNode.specified ? + parseInt( attributeNode.value, 10 ) : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + } + } +}); + +// Hook for boolean attributes +boolHook = { + get: function( elem, name ) { + var + // Use .prop to determine if this attribute is understood as boolean + prop = jQuery.prop( elem, name ), + + // Fetch it accordingly + attr = typeof prop === "boolean" && elem.getAttribute( name ), + detail = typeof prop === "boolean" ? + + getSetInput && getSetAttribute ? + attr != null : + // oldIE fabricates an empty string for missing boolean attributes + // and conflates checked/selected into attroperties + ruseDefault.test( name ) ? + elem[ jQuery.camelCase( "default-" + name ) ] : + !!attr : + + // fetch an attribute node for properties not recognized as boolean + elem.getAttributeNode( name ); + + return detail && detail.value !== false ? + name.toLowerCase() : + undefined; + }, + set: function( elem, value, name ) { + if ( value === false ) { + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) { + // IE<8 needs the *property* name + elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name ); + + // Use defaultChecked and defaultSelected for oldIE + } else { + elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true; + } + + return name; + } +}; + +// fix oldIE value attroperty +if ( !getSetInput || !getSetAttribute ) { + jQuery.attrHooks.value = { + get: function( elem, name ) { + var ret = elem.getAttributeNode( name ); + return jQuery.nodeName( elem, "input" ) ? + + // Ignore the value *property* by using defaultValue + elem.defaultValue : + + ret && ret.specified ? ret.value : undefined; + }, + set: function( elem, value, name ) { + if ( jQuery.nodeName( elem, "input" ) ) { + // Does not return so that setAttribute is also used + elem.defaultValue = value; + } else { + // Use nodeHook if defined (#1954); otherwise setAttribute is fine + return nodeHook && nodeHook.set( elem, value, name ); + } + } + }; +} + +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !getSetAttribute ) { + + // Use this for any attribute in IE6/7 + // This fixes almost every IE6/7 issue + nodeHook = jQuery.valHooks.button = { + get: function( elem, name ) { + var ret = elem.getAttributeNode( name ); + return ret && ( name === "id" || name === "name" || name === "coords" ? ret.value !== "" : ret.specified ) ? + ret.value : + undefined; + }, + set: function( elem, value, name ) { + // Set the existing or create a new attribute node + var ret = elem.getAttributeNode( name ); + if ( !ret ) { + elem.setAttributeNode( + (ret = elem.ownerDocument.createAttribute( name )) + ); + } + + ret.value = value += ""; + + // Break association with cloned elements by also using setAttribute (#9646) + return name === "value" || value === elem.getAttribute( name ) ? + value : + undefined; + } + }; + + // Set contenteditable to false on removals(#10429) + // Setting to empty string throws an error as an invalid value + jQuery.attrHooks.contenteditable = { + get: nodeHook.get, + set: function( elem, value, name ) { + nodeHook.set( elem, value === "" ? false : value, name ); + } + }; + + // Set width and height to auto instead of 0 on empty string( Bug #8150 ) + // This is for removals + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( value === "" ) { + elem.setAttribute( name, "auto" ); + return value; + } + } + }); + }); +} + + +// Some attributes require a special call on IE +// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret = elem.getAttribute( name, 2 ); + return ret == null ? undefined : ret; + } + }); + }); + + // href/src property should get the full normalized URL (#10299/#12915) + jQuery.each([ "href", "src" ], function( i, name ) { + jQuery.propHooks[ name ] = { + get: function( elem ) { + return elem.getAttribute( name, 4 ); + } + }; + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + // Return undefined in the case of empty string + // Note: IE uppercases css property names, but if we were to .toLowerCase() + // .cssText, that would destroy case senstitivity in URL's, like in "background" + return elem.style.cssText || undefined; + }, + set: function( elem, value ) { + return ( elem.style.cssText = value + "" ); + } + }; +} + +// Safari mis-reports the default selected property of an option +// Accessing the parent's selectedIndex property fixes it +if ( !jQuery.support.optSelected ) { + jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { + get: function( elem ) { + var parent = elem.parentNode; + + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + return null; + } + }); +} + +// IE6/7 call enctype encoding +if ( !jQuery.support.enctype ) { + jQuery.propFix.enctype = "encoding"; +} + +// Radios and checkboxes getter/setter +if ( !jQuery.support.checkOn ) { + jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + get: function( elem ) { + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + return elem.getAttribute("value") === null ? "on" : elem.value; + } + }; + }); +} +jQuery.each([ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { + set: function( elem, value ) { + if ( jQuery.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); + } + } + }); +}); +var rformElems = /^(?:input|select|textarea)$/i, + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + var tmp, events, t, handleObjIn, + special, eventHandle, handleObj, + handlers, type, namespaces, origType, + elemData = jQuery._data( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !(events = elemData.events) ) { + events = elemData.events = {}; + } + if ( !(eventHandle = elemData.handle) ) { + eventHandle = elemData.handle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ? + jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : + undefined; + }; + // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events + eventHandle.elem = elem; + } + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = ( types || "" ).match( core_rnotwhite ) || [""]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !(handlers = events[ type ]) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener/attachEvent if the special events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + var j, handleObj, tmp, + origCount, t, events, + special, handlers, type, + namespaces, origType, + elemData = jQuery.hasData( elem ) && jQuery._data( elem ); + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( core_rnotwhite ) || [""]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + delete elemData.handle; + + // removeData also checks for emptiness and clears the expando if empty + // so use it instead of delete + jQuery._removeData( elem, "events" ); + } + }, + + trigger: function( event, data, elem, onlyHandlers ) { + var handle, ontype, cur, + bubbleType, special, tmp, i, + eventPath = [ elem || document ], + type = core_hasOwn.call( event, "type" ) ? event.type : event, + namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf(".") >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf(":") < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + event.isTrigger = true; + event.namespace = namespaces.join("."); + event.namespace_re = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === (elem.ownerDocument || document) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) { + event.preventDefault(); + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Can't use an .isFunction() check here because IE6/7 fails that test. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + try { + elem[ type ](); + } catch ( e ) { + // IE<9 dies on focus/blur to hidden element (#1486,#12518) + // only reproducible on winXP IE8 native, not IE9 in IE8 mode + } + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event ); + + var i, ret, handleObj, matched, j, + handlerQueue = [], + args = core_slice.call( arguments ), + handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). + if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( (event.result = ret) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var sel, handleObj, matches, i, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + // Black-hole SVG instance trees (#13180) + // Avoid non-left-click bubbling in Firefox (#3861) + if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { + + for ( ; cur != this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) { + matches = []; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matches[ sel ] === undefined ) { + matches[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) >= 0 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matches[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, handlers: matches }); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( delegateCount < handlers.length ) { + handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); + } + + return handlerQueue; + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, copy, + type = event.type, + originalEvent = event, + fixHook = this.fixHooks[ type ]; + + if ( !fixHook ) { + this.fixHooks[ type ] = fixHook = + rmouseEvent.test( type ) ? this.mouseHooks : + rkeyEvent.test( type ) ? this.keyHooks : + {}; + } + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = new jQuery.Event( originalEvent ); + + i = copy.length; + while ( i-- ) { + prop = copy[ i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Support: IE<9 + // Fix target property (#1925) + if ( !event.target ) { + event.target = originalEvent.srcElement || document; + } + + // Support: Chrome 23+, Safari? + // Target should not be a text node (#504, #13143) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Support: IE<9 + // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) + event.metaKey = !!event.metaKey; + + return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), + filter: function( event, original ) { + var body, eventDoc, doc, + button = original.button, + fromElement = original.fromElement; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && fromElement ) { + event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + special: { + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { + this.click(); + return false; + } + } + }, + focus: { + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== document.activeElement && this.focus ) { + try { + this.focus(); + return false; + } catch ( e ) { + // Support: IE<9 + // If we error on focus to hidden element (#1486, #12518), + // let .trigger() run the handlers + } + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === document.activeElement && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + + beforeunload: { + postDispatch: function( event ) { + + // Even when returnValue equals to undefined Firefox will still show alert + if ( event.result !== undefined ) { + event.originalEvent.returnValue = event.result; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +jQuery.removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } + } : + function( elem, type, handle ) { + var name = "on" + type; + + if ( elem.detachEvent ) { + + // #8545, #7054, preventing memory leaks for custom events in IE6-8 + // detachEvent needed property on element, by name of that event, to properly expose it to GC + if ( typeof elem[ name ] === core_strundefined ) { + elem[ name ] = null; + } + + elem.detachEvent( name, handle ); + } + }; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || + src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + if ( !e ) { + return; + } + + // If preventDefault exists, run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + + // Support: IE + // Otherwise set the returnValue property of the original event to false + } else { + e.returnValue = false; + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + if ( !e ) { + return; + } + // If stopPropagation exists, run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + + // Support: IE + // Set the cancelBubble property of the original event to true + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + } +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !jQuery.contains( target, related )) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +}); + +// IE submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Lazy-add a submit handler when a descendant form may potentially be submitted + jQuery.event.add( this, "click._submit keypress._submit", function( e ) { + // Node name check avoids a VML-related crash in IE (#9807) + var elem = e.target, + form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; + if ( form && !jQuery._data( form, "submitBubbles" ) ) { + jQuery.event.add( form, "submit._submit", function( event ) { + event._submit_bubble = true; + }); + jQuery._data( form, "submitBubbles", true ); + } + }); + // return undefined since we don't need an event listener + }, + + postDispatch: function( event ) { + // If form was submitted by the user, bubble the event up the tree + if ( event._submit_bubble ) { + delete event._submit_bubble; + if ( this.parentNode && !event.isTrigger ) { + jQuery.event.simulate( "submit", this.parentNode, event, true ); + } + } + }, + + teardown: function() { + // Only need this for delegated form submit events + if ( jQuery.nodeName( this, "form" ) ) { + return false; + } + + // Remove delegated handlers; cleanData eventually reaps submit handlers attached above + jQuery.event.remove( this, "._submit" ); + } + }; +} + +// IE change delegation and checkbox/radio fix +if ( !jQuery.support.changeBubbles ) { + + jQuery.event.special.change = { + + setup: function() { + + if ( rformElems.test( this.nodeName ) ) { + // IE doesn't fire change on a check/radio until blur; trigger it on click + // after a propertychange. Eat the blur-change in special.change.handle. + // This still fires onchange a second time for check/radio after blur. + if ( this.type === "checkbox" || this.type === "radio" ) { + jQuery.event.add( this, "propertychange._change", function( event ) { + if ( event.originalEvent.propertyName === "checked" ) { + this._just_changed = true; + } + }); + jQuery.event.add( this, "click._change", function( event ) { + if ( this._just_changed && !event.isTrigger ) { + this._just_changed = false; + } + // Allow triggered, simulated change events (#11500) + jQuery.event.simulate( "change", this, event, true ); + }); + } + return false; + } + // Delegated event; lazy-add a change handler on descendant inputs + jQuery.event.add( this, "beforeactivate._change", function( e ) { + var elem = e.target; + + if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) { + jQuery.event.add( elem, "change._change", function( event ) { + if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { + jQuery.event.simulate( "change", this.parentNode, event, true ); + } + }); + jQuery._data( elem, "changeBubbles", true ); + } + }); + }, + + handle: function( event ) { + var elem = event.target; + + // Swallow native change events from checkbox/radio, we already triggered them above + if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { + return event.handleObj.handler.apply( this, arguments ); + } + }, + + teardown: function() { + jQuery.event.remove( this, "._change" ); + + return !rformElems.test( this.nodeName ); + } + }; +} + +// Create "bubbling" focus and blur events +if ( !jQuery.support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler while someone wants focusin/focusout + var attaches = 0, + handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + if ( attaches++ === 0 ) { + document.addEventListener( orig, handler, true ); + } + }, + teardown: function() { + if ( --attaches === 0 ) { + document.removeEventListener( orig, handler, true ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var type, origFn; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on( types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + bind: function( types, data, fn ) { + return this.on( types, null, data, fn ); + }, + unbind: function( types, fn ) { + return this.off( types, null, fn ); + }, + + delegate: function( selector, types, data, fn ) { + return this.on( types, selector, data, fn ); + }, + undelegate: function( selector, types, fn ) { + // ( namespace ) or ( selector, types [, fn] ) + return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + var elem = this[0]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +}); +/*! + * Sizzle CSS Selector Engine + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license + * http://sizzlejs.com/ + */ +(function( window, undefined ) { + +var i, + cachedruns, + Expr, + getText, + isXML, + compile, + hasDuplicate, + outermostContext, + + // Local document vars + setDocument, + document, + docElem, + documentIsXML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + sortOrder, + + // Instance-specific data + expando = "sizzle" + -(new Date()), + preferredDoc = window.document, + support = {}, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + + // General-purpose constants + strundefined = typeof undefined, + MAX_NEGATIVE = 1 << 31, + + // Array methods + arr = [], + pop = arr.pop, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf if we can't use a native one + indexOf = arr.indexOf || function( elem ) { + var i = 0, + len = this.length; + for ( ; i < len; i++ ) { + if ( this[i] === elem ) { + return i; + } + } + return -1; + }, + + + // Regular expressions + + // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + // http://www.w3.org/TR/css3-syntax/#characters + characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", + + // Loosely modeled on CSS identifier characters + // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors + // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = characterEncoding.replace( "w", "w#" ), + + // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors + operators = "([*^$|!~]?=)", + attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + + "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", + + // Prefer arguments quoted, + // then not containing pseudos/brackets, + // then attribute selectors/non-parenthetical expressions, + // then anything else + // These preferences are here to reduce the number of selectors + // needing tokenize in the PSEUDO preFilter + pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ), + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + characterEncoding + ")" ), + "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), + "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ), + "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rsibling = /[\x20\t\r\n\f]*[+~]/, + + rnative = /^[^{]+\{\s*\[native code/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rescape = /'|\\/g, + rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g, + + // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = /\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g, + funescape = function( _, escaped ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + return high !== high ? + escaped : + // BMP codepoint + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }; + +// Use a stripped-down slice if we can't use a native one +try { + slice.call( preferredDoc.documentElement.childNodes, 0 )[0].nodeType; +} catch ( e ) { + slice = function( i ) { + var elem, + results = []; + while ( (elem = this[i++]) ) { + results.push( elem ); + } + return results; + }; +} + +/** + * For feature detection + * @param {Function} fn The function to test for native support + */ +function isNative( fn ) { + return rnative.test( fn + "" ); +} + +/** + * Create key-value caches of limited size + * @returns {Function(string, Object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var cache, + keys = []; + + return (cache = function( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key += " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key ] = value); + }); +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created div and expects a boolean result + */ +function assert( fn ) { + var div = document.createElement("div"); + + try { + return fn( div ); + } catch (e) { + return false; + } finally { + // release memory in IE + div = null; + } +} + +function Sizzle( selector, context, results, seed ) { + var match, elem, m, nodeType, + // QSA vars + i, groups, old, nid, newContext, newSelector; + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + + context = context || document; + results = results || []; + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) { + return []; + } + + if ( !documentIsXML && !seed ) { + + // Shortcuts + if ( (match = rquickExpr.exec( selector )) ) { + // Speed-up: Sizzle("#ID") + if ( (m = match[1]) ) { + if ( nodeType === 9 ) { + elem = context.getElementById( m ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + if ( elem && elem.parentNode ) { + // Handle the case where IE, Opera, and Webkit return items + // by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + } else { + // Context is not a document + if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && + contains( context, elem ) && elem.id === m ) { + results.push( elem ); + return results; + } + } + + // Speed-up: Sizzle("TAG") + } else if ( match[2] ) { + push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) ); + return results; + + // Speed-up: Sizzle(".CLASS") + } else if ( (m = match[3]) && support.getByClassName && context.getElementsByClassName ) { + push.apply( results, slice.call(context.getElementsByClassName( m ), 0) ); + return results; + } + } + + // QSA path + if ( support.qsa && !rbuggyQSA.test(selector) ) { + old = true; + nid = expando; + newContext = context; + newSelector = nodeType === 9 && selector; + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + groups = tokenize( selector ); + + if ( (old = context.getAttribute("id")) ) { + nid = old.replace( rescape, "\\$&" ); + } else { + context.setAttribute( "id", nid ); + } + nid = "[id='" + nid + "'] "; + + i = groups.length; + while ( i-- ) { + groups[i] = nid + toSelector( groups[i] ); + } + newContext = rsibling.test( selector ) && context.parentNode || context; + newSelector = groups.join(","); + } + + if ( newSelector ) { + try { + push.apply( results, slice.call( newContext.querySelectorAll( + newSelector + ), 0 ) ); + return results; + } catch(qsaError) { + } finally { + if ( !old ) { + context.removeAttribute("id"); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Detect xml + * @param {Element|Object} elem An element or a document + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var doc = node ? node.ownerDocument || node : preferredDoc; + + // If no document and documentElement is available, return + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Set our document + document = doc; + docElem = doc.documentElement; + + // Support tests + documentIsXML = isXML( doc ); + + // Check if getElementsByTagName("*") returns only elements + support.tagNameNoComments = assert(function( div ) { + div.appendChild( doc.createComment("") ); + return !div.getElementsByTagName("*").length; + }); + + // Check if attributes should be retrieved by attribute nodes + support.attributes = assert(function( div ) { + div.innerHTML = ""; + var type = typeof div.lastChild.getAttribute("multiple"); + // IE8 returns a string for some attributes even when not present + return type !== "boolean" && type !== "string"; + }); + + // Check if getElementsByClassName can be trusted + support.getByClassName = assert(function( div ) { + // Opera can't find a second classname (in 9.6) + div.innerHTML = ""; + if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) { + return false; + } + + // Safari 3.2 caches class attributes and doesn't catch changes + div.lastChild.className = "e"; + return div.getElementsByClassName("e").length === 2; + }); + + // Check if getElementById returns elements by name + // Check if getElementsByName privileges form controls or returns elements by ID + support.getByName = assert(function( div ) { + // Inject content + div.id = expando + 0; + div.innerHTML = "
    "; + docElem.insertBefore( div, docElem.firstChild ); + + // Test + var pass = doc.getElementsByName && + // buggy browsers will return fewer than the correct 2 + doc.getElementsByName( expando ).length === 2 + + // buggy browsers will return more than the correct 0 + doc.getElementsByName( expando + 0 ).length; + support.getIdNotName = !doc.getElementById( expando ); + + // Cleanup + docElem.removeChild( div ); + + return pass; + }); + + // IE6/7 return modified attributes + Expr.attrHandle = assert(function( div ) { + div.innerHTML = ""; + return div.firstChild && typeof div.firstChild.getAttribute !== strundefined && + div.firstChild.getAttribute("href") === "#"; + }) ? + {} : + { + "href": function( elem ) { + return elem.getAttribute( "href", 2 ); + }, + "type": function( elem ) { + return elem.getAttribute("type"); + } + }; + + // ID find and filter + if ( support.getIdNotName ) { + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== strundefined && !documentIsXML ) { + var m = context.getElementById( id ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [m] : []; + } + }; + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + } else { + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== strundefined && !documentIsXML ) { + var m = context.getElementById( id ); + + return m ? + m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ? + [m] : + undefined : + []; + } + }; + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + } + + // Tag + Expr.find["TAG"] = support.tagNameNoComments ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== strundefined ) { + return context.getElementsByTagName( tag ); + } + } : + function( tag, context ) { + var elem, + tmp = [], + i = 0, + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Name + Expr.find["NAME"] = support.getByName && function( tag, context ) { + if ( typeof context.getElementsByName !== strundefined ) { + return context.getElementsByName( name ); + } + }; + + // Class + Expr.find["CLASS"] = support.getByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== strundefined && !documentIsXML ) { + return context.getElementsByClassName( className ); + } + }; + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21), + // no need to also add to buggyMatches since matches checks buggyQSA + // A support test would require too much code (would include document ready) + rbuggyQSA = [ ":focus" ]; + + if ( (support.qsa = isNative(doc.querySelectorAll)) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( div ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explictly + // setting a boolean content attribute, + // since its presence should be enough + // http://bugs.jquery.com/ticket/12359 + div.innerHTML = ""; + + // IE8 - Some boolean attributes are not treated correctly + if ( !div.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + }); + + assert(function( div ) { + + // Opera 10-12/IE8 - ^= $= *= and empty values + // Should not select anything + div.innerHTML = ""; + if ( div.querySelectorAll("[i^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":enabled").length ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + div.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = isNative( (matches = docElem.matchesSelector || + docElem.mozMatchesSelector || + docElem.webkitMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( div ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( div, "div" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( div, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = new RegExp( rbuggyMatches.join("|") ); + + // Element contains another + // Purposefully does not implement inclusive descendent + // As in, an element does not contain itself + contains = isNative(docElem.contains) || docElem.compareDocumentPosition ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + // Document order sorting + sortOrder = docElem.compareDocumentPosition ? + function( a, b ) { + var compare; + + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + if ( (compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b )) ) { + if ( compare & 1 || a.parentNode && a.parentNode.nodeType === 11 ) { + if ( a === doc || contains( preferredDoc, a ) ) { + return -1; + } + if ( b === doc || contains( preferredDoc, b ) ) { + return 1; + } + return 0; + } + return compare & 4 ? -1 : 1; + } + + return a.compareDocumentPosition ? -1 : 1; + } : + function( a, b ) { + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + + // Parentless nodes are either documents or disconnected + } else if ( !aup || !bup ) { + return a === doc ? -1 : + b === doc ? 1 : + aup ? -1 : + bup ? 1 : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + // Always assume the presence of duplicates if sort doesn't + // pass them to our comparison function (as in Google Chrome). + hasDuplicate = false; + [0, 0].sort( sortOrder ); + support.detectDuplicates = hasDuplicate; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + // rbuggyQSA always contains :focus, so no need for an existence check + if ( support.matchesSelector && !documentIsXML && (!rbuggyMatches || !rbuggyMatches.test(expr)) && !rbuggyQSA.test(expr) ) { + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch(e) {} + } + + return Sizzle( expr, document, null, [elem] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + var val; + + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + if ( !documentIsXML ) { + name = name.toLowerCase(); + } + if ( (val = Expr.attrHandle[ name ]) ) { + return val( elem ); + } + if ( documentIsXML || support.attributes ) { + return elem.getAttribute( name ); + } + return ( (val = elem.getAttributeNode( name )) || elem.getAttribute( name ) ) && elem[ name ] === true ? + name : + val && val.specified ? val.value : null; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +// Document sorting and removing duplicates +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + i = 1, + j = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + results.sort( sortOrder ); + + if ( hasDuplicate ) { + for ( ; (elem = results[i]); i++ ) { + if ( elem === results[ i - 1 ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + return results; +}; + +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && ( ~b.sourceIndex || MAX_NEGATIVE ) - ( ~a.sourceIndex || MAX_NEGATIVE ); + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +// Returns a function to use in pseudos for input types +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +// Returns a function to use in pseudos for buttons +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +// Returns a function to use in pseudos for positionals +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + for ( ; (node = elem[i]); i++ ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (see #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[5] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[4] ) { + match[2] = match[4]; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeName ) { + if ( nodeName === "*" ) { + return function() { return true; }; + } + + nodeName = nodeName.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, outerCache, node, diff, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + // Seek `elem` from a previously-cached index + outerCache = parent[ expando ] || (parent[ expando ] = {}); + cache = outerCache[ type ] || []; + nodeIndex = cache[0] === dirruns && cache[1]; + diff = cache[0] === dirruns && cache[2]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + outerCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + // Use previously-cached element index if available + } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { + diff = cache[1]; + + // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) + } else { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { + // Cache the index of each encountered element + if ( useCache ) { + (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf.call( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifider + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsXML ? + elem.getAttribute("xml:lang") || elem.getAttribute("lang") : + elem.lang) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": function( elem ) { + return elem.disabled === false; + }, + + "disabled": function( elem ) { + return elem.disabled === true; + }, + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), + // not comment, processing instructions, or others + // Thanks to Diego Perini for the nodeName shortcut + // Greater than "@" means alpha characters (specifically not starting with "#" or "?") + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) + // use getAttribute instead to test this case + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +function tokenize( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( tokens = [] ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push( { + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +} + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + checkNonElements = base && dir === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var data, cache, outerCache, + dirkey = dirruns + " " + doneName; + + // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) { + if ( (data = cache[1]) === true || data === cachedruns ) { + return data === true; + } + } else { + cache = outerCache[ dir ] = [ dirkey ]; + cache[1] = matcher( elem, context, xml ) || cachedruns; + if ( cache[1] === true ) { + return true; + } + } + } + } + } + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf.call( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( tokens.slice( 0, i - 1 ) ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + // A counter to specify which element is currently being matched + var matcherCachedRuns = 0, + bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, expandContext ) { + var elem, j, matcher, + setMatched = [], + matchedCount = 0, + i = "0", + unmatched = seed && [], + outermost = expandContext != null, + contextBackup = outermostContext, + // We must always have either seed elements or context + elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1); + + if ( outermost ) { + outermostContext = context !== document && context; + cachedruns = matcherCachedRuns; + } + + // Add elements passing elementMatchers directly to results + // Keep `i` a string if there are no elements so `matchedCount` will be "00" below + for ( ; (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + cachedruns = ++matcherCachedRuns; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // Apply set filters to unmatched elements + matchedCount += i; + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !group ) { + group = tokenize( selector ); + } + i = group.length; + while ( i-- ) { + cached = matcherFromTokens( group[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + } + return cached; +}; + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function select( selector, context, results, seed ) { + var i, tokens, token, type, find, + match = tokenize( selector ); + + if ( !seed ) { + // Try to minimize operations if there is only one group + if ( match.length === 1 ) { + + // Take a shortcut and set the context if the root selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + context.nodeType === 9 && !documentIsXML && + Expr.relative[ tokens[1].type ] ) { + + context = Expr.find["ID"]( token.matches[0].replace( runescape, funescape ), context )[0]; + if ( !context ) { + return results; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && context.parentNode || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, slice.call( seed, 0 ) ); + return results; + } + + break; + } + } + } + } + } + + // Compile and execute a filtering function + // Provide `match` to avoid retokenization if we modified the selector above + compile( selector, match )( + seed, + context, + documentIsXML, + results, + rsibling.test( selector ) + ); + return results; +} + +// Deprecated +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Easy API for creating new setFilters +function setFilters() {} +Expr.filters = setFilters.prototype = Expr.pseudos; +Expr.setFilters = new setFilters(); + +// Initialize with the default document +setDocument(); + +// Override sizzle attribute retrieval +Sizzle.attr = jQuery.attr; +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.pseudos; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + +})( window ); +var runtil = /Until$/, + rparentsprev = /^(?:parents|prev(?:Until|All))/, + isSimple = /^.[^:#\[\.,]*$/, + rneedsContext = jQuery.expr.match.needsContext, + // methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend({ + find: function( selector ) { + var i, ret, self, + len = this.length; + + if ( typeof selector !== "string" ) { + self = this; + return this.pushStack( jQuery( selector ).filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }) ); + } + + ret = []; + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, this[ i ], ret ); + } + + // Needed because $( selector, context ) becomes $( context ).find( selector ) + ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); + ret.selector = ( this.selector ? this.selector + " " : "" ) + selector; + return ret; + }, + + has: function( target ) { + var i, + targets = jQuery( target, this ), + len = targets.length; + + return this.filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false) ); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true) ); + }, + + is: function( selector ) { + return !!selector && ( + typeof selector === "string" ? + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + rneedsContext.test( selector ) ? + jQuery( selector, this.context ).index( this[0] ) >= 0 : + jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0 ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + ret = [], + pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( ; i < l; i++ ) { + cur = this[i]; + + while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) { + if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { + ret.push( cur ); + break; + } + cur = cur.parentNode; + } + } + + return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1; + } + + // index in selector + if ( typeof elem === "string" ) { + return jQuery.inArray( this[0], jQuery( elem ) ); + } + + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + var set = typeof selector === "string" ? + jQuery( selector, context ) : + jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( jQuery.unique(all) ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter(selector) + ); + } +}); + +jQuery.fn.andSelf = jQuery.fn.addBack; + +function sibling( cur, dir ) { + do { + cur = cur[ dir ]; + } while ( cur && cur.nodeType !== 1 ); + + return cur; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; + + if ( this.length > 1 && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 ? + jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : + jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + var matched = [], + cur = elem[ dir ]; + + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, keep ) { + + // Can't pass null or undefined to indexOf in Firefox 4 + // Set to 0 to skip string check + qualifier = qualifier || 0; + + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + var retVal = !!qualifier.call( elem, i, elem ); + return retVal === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem ) { + return ( elem === qualifier ) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem ) { + return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; + }); +} +function createSafeFragment( document ) { + var list = nodeNames.split( "|" ), + safeFrag = document.createDocumentFragment(); + + if ( safeFrag.createElement ) { + while ( list.length ) { + safeFrag.createElement( + list.pop() + ); + } + } + return safeFrag; +} + +var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", + rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, + rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"), + rleadingWhitespace = /^\s+/, + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, + rtagName = /<([\w:]+)/, + rtbody = /\s*$/g, + + // We have to close these tags to support XHTML (#13200) + wrapMap = { + option: [ 1, "" ], + legend: [ 1, "
    ", "
    " ], + area: [ 1, "", "" ], + param: [ 1, "", "" ], + thead: [ 1, "", "
    " ], + tr: [ 2, "", "
    " ], + col: [ 2, "", "
    " ], + td: [ 3, "", "
    " ], + + // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, + // unless wrapped in a div with non-breaking characters in front of it. + _default: jQuery.support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X
    ", "
    " ] + }, + safeFragment = createSafeFragment( document ), + fragmentDiv = safeFragment.appendChild( document.createElement("div") ); + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +jQuery.fn.extend({ + text: function( value ) { + return jQuery.access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); + }, null, value, arguments.length ); + }, + + wrapAll: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each(function(i) { + jQuery(this).wrapAll( html.call(this, i) ); + }); + } + + if ( this[0] ) { + // The elements to wrap the target around + var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); + + if ( this[0].parentNode ) { + wrap.insertBefore( this[0] ); + } + + wrap.map(function() { + var elem = this; + + while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { + elem = elem.firstChild; + } + + return elem; + }).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( jQuery.isFunction( html ) ) { + return this.each(function(i) { + jQuery(this).wrapInner( html.call(this, i) ); + }); + } + + return this.each(function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + }); + }, + + wrap: function( html ) { + var isFunction = jQuery.isFunction( html ); + + return this.each(function(i) { + jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); + }); + }, + + unwrap: function() { + return this.parent().each(function() { + if ( !jQuery.nodeName( this, "body" ) ) { + jQuery( this ).replaceWith( this.childNodes ); + } + }).end(); + }, + + append: function() { + return this.domManip(arguments, true, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.appendChild( elem ); + } + }); + }, + + prepend: function() { + return this.domManip(arguments, true, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.insertBefore( elem, this.firstChild ); + } + }); + }, + + before: function() { + return this.domManip( arguments, false, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + }); + }, + + after: function() { + return this.domManip( arguments, false, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + }); + }, + + // keepData is for internal use only--do not document + remove: function( selector, keepData ) { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + if ( !selector || jQuery.filter( selector, [ elem ] ).length > 0 ) { + if ( !keepData && elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem ) ); + } + + if ( elem.parentNode ) { + if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { + setGlobalEval( getAll( elem, "script" ) ); + } + elem.parentNode.removeChild( elem ); + } + } + } + + return this; + }, + + empty: function() { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + } + + // Remove any remaining nodes + while ( elem.firstChild ) { + elem.removeChild( elem.firstChild ); + } + + // If this is a select, ensure that it displays empty (#12336) + // Support: IE<9 + if ( elem.options && jQuery.nodeName( elem, "select" ) ) { + elem.options.length = 0; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function () { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + }); + }, + + html: function( value ) { + return jQuery.access( this, function( value ) { + var elem = this[0] || {}, + i = 0, + l = this.length; + + if ( value === undefined ) { + return elem.nodeType === 1 ? + elem.innerHTML.replace( rinlinejQuery, "" ) : + undefined; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) && + ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && + !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { + + value = value.replace( rxhtmlTag, "<$1>" ); + + try { + for (; i < l; i++ ) { + // Remove element nodes and prevent memory leaks + elem = this[i] || {}; + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch(e) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function( value ) { + var isFunc = jQuery.isFunction( value ); + + // Make sure that the elements are removed from the DOM before they are inserted + // this can help fix replacing a parent with child elements + if ( !isFunc && typeof value !== "string" ) { + value = jQuery( value ).not( this ).detach(); + } + + return this.domManip( [ value ], true, function( elem ) { + var next = this.nextSibling, + parent = this.parentNode; + + if ( parent ) { + jQuery( this ).remove(); + parent.insertBefore( elem, next ); + } + }); + }, + + detach: function( selector ) { + return this.remove( selector, true ); + }, + + domManip: function( args, table, callback ) { + + // Flatten any nested arrays + args = core_concat.apply( [], args ); + + var first, node, hasScripts, + scripts, doc, fragment, + i = 0, + l = this.length, + set = this, + iNoClone = l - 1, + value = args[0], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) { + return this.each(function( index ) { + var self = set.eq( index ); + if ( isFunction ) { + args[0] = value.call( this, index, table ? self.html() : undefined ); + } + self.domManip( args, table, callback ); + }); + } + + if ( l ) { + fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + if ( first ) { + table = table && jQuery.nodeName( first, "tr" ); + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( + table && jQuery.nodeName( this[i], "table" ) ? + findOrAppend( this[i], "tbody" ) : + this[i], + node, + i + ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) { + + if ( node.src ) { + // Hope ajax is available... + jQuery.ajax({ + url: node.src, + type: "GET", + dataType: "script", + async: false, + global: false, + "throws": true + }); + } else { + jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) ); + } + } + } + } + + // Fix #11809: Avoid leaking memory + fragment = first = null; + } + } + + return this; + } +}); + +function findOrAppend( elem, tag ) { + return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) ); +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + var attr = elem.getAttributeNode("type"); + elem.type = ( attr && attr.specified ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + if ( match ) { + elem.type = match[1]; + } else { + elem.removeAttribute("type"); + } + return elem; +} + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var elem, + i = 0; + for ( ; (elem = elems[i]) != null; i++ ) { + jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) ); + } +} + +function cloneCopyEvent( src, dest ) { + + if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { + return; + } + + var type, i, l, + oldData = jQuery._data( src ), + curData = jQuery._data( dest, oldData ), + events = oldData.events; + + if ( events ) { + delete curData.handle; + curData.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + + // make the cloned public data object a copy from the original + if ( curData.data ) { + curData.data = jQuery.extend( {}, curData.data ); + } +} + +function fixCloneNodeIssues( src, dest ) { + var nodeName, e, data; + + // We do not need to do anything for non-Elements + if ( dest.nodeType !== 1 ) { + return; + } + + nodeName = dest.nodeName.toLowerCase(); + + // IE6-8 copies events bound via attachEvent when using cloneNode. + if ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) { + data = jQuery._data( dest ); + + for ( e in data.events ) { + jQuery.removeEvent( dest, e, data.handle ); + } + + // Event data gets referenced instead of copied if the expando gets copied too + dest.removeAttribute( jQuery.expando ); + } + + // IE blanks contents when cloning scripts, and tries to evaluate newly-set text + if ( nodeName === "script" && dest.text !== src.text ) { + disableScript( dest ).text = src.text; + restoreScript( dest ); + + // IE6-10 improperly clones children of object elements using classid. + // IE10 throws NoModificationAllowedError if parent is null, #12132. + } else if ( nodeName === "object" ) { + if ( dest.parentNode ) { + dest.outerHTML = src.outerHTML; + } + + // This path appears unavoidable for IE9. When cloning an object + // element in IE9, the outerHTML strategy above is not sufficient. + // If the src has innerHTML and the destination does not, + // copy the src.innerHTML into the dest.innerHTML. #10324 + if ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) { + dest.innerHTML = src.innerHTML; + } + + } else if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) { + // IE6-8 fails to persist the checked state of a cloned checkbox + // or radio button. Worse, IE6-7 fail to give the cloned element + // a checked appearance if the defaultChecked value isn't also set + + dest.defaultChecked = dest.checked = src.checked; + + // IE6-7 get confused and end up setting the value of a cloned + // checkbox/radio button to an empty string instead of "on" + if ( dest.value !== src.value ) { + dest.value = src.value; + } + + // IE6-8 fails to return the selected option to the default selected + // state when cloning options + } else if ( nodeName === "option" ) { + dest.defaultSelected = dest.selected = src.defaultSelected; + + // IE6-8 fails to set the defaultValue to the correct value when + // cloning other types of input fields + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +jQuery.each({ + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + i = 0, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone(true); + jQuery( insert[i] )[ original ]( elems ); + + // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() + core_push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +}); + +function getAll( context, tag ) { + var elems, elem, + i = 0, + found = typeof context.getElementsByTagName !== core_strundefined ? context.getElementsByTagName( tag || "*" ) : + typeof context.querySelectorAll !== core_strundefined ? context.querySelectorAll( tag || "*" ) : + undefined; + + if ( !found ) { + for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) { + if ( !tag || jQuery.nodeName( elem, tag ) ) { + found.push( elem ); + } else { + jQuery.merge( found, getAll( elem, tag ) ); + } + } + } + + return tag === undefined || tag && jQuery.nodeName( context, tag ) ? + jQuery.merge( [ context ], found ) : + found; +} + +// Used in buildFragment, fixes the defaultChecked property +function fixDefaultChecked( elem ) { + if ( manipulation_rcheckableType.test( elem.type ) ) { + elem.defaultChecked = elem.checked; + } +} + +jQuery.extend({ + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var destElements, node, clone, i, srcElements, + inPage = jQuery.contains( elem.ownerDocument, elem ); + + if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { + clone = elem.cloneNode( true ); + + // IE<=8 does not properly clone detached, unknown element nodes + } else { + fragmentDiv.innerHTML = elem.outerHTML; + fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); + } + + if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && + (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { + + // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + // Fix all IE cloning issues + for ( i = 0; (node = srcElements[i]) != null; ++i ) { + // Ensure that the destination node is not null; Fixes #9587 + if ( destElements[i] ) { + fixCloneNodeIssues( node, destElements[i] ); + } + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0; (node = srcElements[i]) != null; i++ ) { + cloneCopyEvent( node, destElements[i] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + destElements = srcElements = node = null; + + // Return the cloned set + return clone; + }, + + buildFragment: function( elems, context, scripts, selection ) { + var j, elem, contains, + tmp, tag, tbody, wrap, + l = elems.length, + + // Ensure a safe fragment + safe = createSafeFragment( context ), + + nodes = [], + i = 0; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || safe.appendChild( context.createElement("div") ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + + tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1>" ) + wrap[2]; + + // Descend through wrappers to the right content + j = wrap[0]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Manually add leading whitespace removed by IE + if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { + nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) ); + } + + // Remove IE's autoinserted from table fragments + if ( !jQuery.support.tbody ) { + + // String was a , *may* have spurious + elem = tag === "table" && !rtbody.test( elem ) ? + tmp.firstChild : + + // String was a bare or + wrap[1] === "
    " && !rtbody.test( elem ) ? + tmp : + 0; + + j = elem && elem.childNodes.length; + while ( j-- ) { + if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) { + elem.removeChild( tbody ); + } + } + } + + jQuery.merge( nodes, tmp.childNodes ); + + // Fix #12392 for WebKit and IE > 9 + tmp.textContent = ""; + + // Fix #12392 for oldIE + while ( tmp.firstChild ) { + tmp.removeChild( tmp.firstChild ); + } + + // Remember the top-level container for proper cleanup + tmp = safe.lastChild; + } + } + } + + // Fix #11356: Clear elements from fragment + if ( tmp ) { + safe.removeChild( tmp ); + } + + // Reset defaultChecked for any radios and checkboxes + // about to be appended to the DOM in IE 6/7 (#8060) + if ( !jQuery.support.appendChecked ) { + jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); + } + + i = 0; + while ( (elem = nodes[ i++ ]) ) { + + // #4087 - If origin and destination elements are the same, and this is + // that element, do not do anything + if ( selection && jQuery.inArray( elem, selection ) !== -1 ) { + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( safe.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( (elem = tmp[ j++ ]) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + tmp = null; + + return safe; + }, + + cleanData: function( elems, /* internal */ acceptData ) { + var elem, type, id, data, + i = 0, + internalKey = jQuery.expando, + cache = jQuery.cache, + deleteExpando = jQuery.support.deleteExpando, + special = jQuery.event.special; + + for ( ; (elem = elems[i]) != null; i++ ) { + + if ( acceptData || jQuery.acceptData( elem ) ) { + + id = elem[ internalKey ]; + data = id && cache[ id ]; + + if ( data ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Remove cache only if it was not already removed by jQuery.event.remove + if ( cache[ id ] ) { + + delete cache[ id ]; + + // IE does not allow us to delete expando properties from nodes, + // nor does it have a removeAttribute function on Document nodes; + // we must handle all of these cases + if ( deleteExpando ) { + delete elem[ internalKey ]; + + } else if ( typeof elem.removeAttribute !== core_strundefined ) { + elem.removeAttribute( internalKey ); + + } else { + elem[ internalKey ] = null; + } + + core_deletedIds.push( id ); + } + } + } + } + } +}); +var iframe, getStyles, curCSS, + ralpha = /alpha\([^)]*\)/i, + ropacity = /opacity\s*=\s*([^)]*)/, + rposition = /^(top|right|bottom|left)$/, + // swappable if display is none or starts with table except "table", "table-cell", or "table-caption" + // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rmargin = /^margin/, + rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ), + rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ), + rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ), + elemdisplay = { BODY: "block" }, + + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: 0, + fontWeight: 400 + }, + + cssExpand = [ "Top", "Right", "Bottom", "Left" ], + cssPrefixes = [ "Webkit", "O", "Moz", "ms" ]; + +// return a css property mapped to a potentially vendor prefixed property +function vendorPropName( style, name ) { + + // shortcut for names that are not vendor prefixed + if ( name in style ) { + return name; + } + + // check for vendor prefixed names + var capName = name.charAt(0).toUpperCase() + name.slice(1), + origName = name, + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in style ) { + return name; + } + } + + return origName; +} + +function isHidden( elem, el ) { + // isHidden might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); +} + +function showHide( elements, show ) { + var display, elem, hidden, + values = [], + index = 0, + length = elements.length; + + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + values[ index ] = jQuery._data( elem, "olddisplay" ); + display = elem.style.display; + if ( show ) { + // Reset the inline display of this element to learn if it is + // being hidden by cascaded rules or not + if ( !values[ index ] && display === "none" ) { + elem.style.display = ""; + } + + // Set elements which have been overridden with display: none + // in a stylesheet to whatever the default browser style is + // for such an element + if ( elem.style.display === "" && isHidden( elem ) ) { + values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); + } + } else { + + if ( !values[ index ] ) { + hidden = isHidden( elem ); + + if ( display && display !== "none" || !hidden ) { + jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) ); + } + } + } + } + + // Set the display of most of the elements in a second loop + // to avoid the constant reflow + for ( index = 0; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + if ( !show || elem.style.display === "none" || elem.style.display === "" ) { + elem.style.display = show ? values[ index ] || "" : "none"; + } + } + + return elements; +} + +jQuery.fn.extend({ + css: function( name, value ) { + return jQuery.access( this, function( elem, name, value ) { + var len, styles, + map = {}, + i = 0; + + if ( jQuery.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + }, + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + var bool = typeof state === "boolean"; + + return this.each(function() { + if ( bool ? state : isHidden( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + }); + } +}); + +jQuery.extend({ + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Exclude the following css properties to add px + cssNumber: { + "columnCount": true, + "fillOpacity": true, + "fontWeight": true, + "lineHeight": true, + "opacity": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: { + // normalize float css property + "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat" + }, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = jQuery.camelCase( name ), + style = elem.style; + + name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); + + // gets hook for the prefixed version + // followed by the unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // convert relative number strings (+= or -=) to relative numbers. #7345 + if ( type === "string" && (ret = rrelNum.exec( value )) ) { + value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); + // Fixes bug #9237 + type = "number"; + } + + // Make sure that NaN and null values aren't set. See: #7116 + if ( value == null || type === "number" && isNaN( value ) ) { + return; + } + + // If a number was passed in, add 'px' to the (except for certain CSS properties) + if ( type === "number" && !jQuery.cssNumber[ origName ] ) { + value += "px"; + } + + // Fixes #8908, it can be done more correctly by specifing setters in cssHooks, + // but it would mean to define eight (for every problematic property) identical functions + if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { + + // Wrapped to prevent IE from throwing errors when 'invalid' values are provided + // Fixes bug #5509 + try { + style[ name ] = value; + } catch(e) {} + } + + } else { + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var num, val, hooks, + origName = jQuery.camelCase( name ); + + // Make sure that we're working with the right name + name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); + + // gets hook for the prefixed version + // followed by the unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + //convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Return, converting to number if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || jQuery.isNumeric( num ) ? num || 0 : val; + } + return val; + }, + + // A method for quickly swapping in/out CSS properties to get correct calculations + swap: function( elem, options, callback, args ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.apply( elem, args || [] ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; + } +}); + +// NOTE: we've included the "window" in window.getComputedStyle +// because jsdom on node.js will break without it. +if ( window.getComputedStyle ) { + getStyles = function( elem ) { + return window.getComputedStyle( elem, null ); + }; + + curCSS = function( elem, name, _computed ) { + var width, minWidth, maxWidth, + computed = _computed || getStyles( elem ), + + // getPropertyValue is only needed for .css('filter') in IE9, see #12537 + ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined, + style = elem.style; + + if ( computed ) { + + if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right + // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels + // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values + if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret; + }; +} else if ( document.documentElement.currentStyle ) { + getStyles = function( elem ) { + return elem.currentStyle; + }; + + curCSS = function( elem, name, _computed ) { + var left, rs, rsLeft, + computed = _computed || getStyles( elem ), + ret = computed ? computed[ name ] : undefined, + style = elem.style; + + // Avoid setting ret to empty string here + // so we don't default to auto + if ( ret == null && style && style[ name ] ) { + ret = style[ name ]; + } + + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels + // but not position css attributes, as those are proportional to the parent element instead + // and we can't measure the parent instead because it might trigger a "stacking dolls" problem + if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { + + // Remember the original values + left = style.left; + rs = elem.runtimeStyle; + rsLeft = rs && rs.left; + + // Put in the new values to get a computed value out + if ( rsLeft ) { + rs.left = elem.currentStyle.left; + } + style.left = name === "fontSize" ? "1em" : ret; + ret = style.pixelLeft + "px"; + + // Revert the changed values + style.left = left; + if ( rsLeft ) { + rs.left = rsLeft; + } + } + + return ret === "" ? "auto" : ret; + }; +} + +function setPositiveNumber( elem, value, subtract ) { + var matches = rnumsplit.exec( value ); + return matches ? + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : + value; +} + +function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { + var i = extra === ( isBorderBox ? "border" : "content" ) ? + // If we already have the right measurement, avoid augmentation + 4 : + // Otherwise initialize for horizontal or vertical properties + name === "width" ? 1 : 0, + + val = 0; + + for ( ; i < 4; i += 2 ) { + // both box models exclude margin, so add it if we want it + if ( extra === "margin" ) { + val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); + } + + if ( isBorderBox ) { + // border-box includes padding, so remove it if we want content + if ( extra === "content" ) { + val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // at this point, extra isn't border nor margin, so remove border + if ( extra !== "margin" ) { + val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } else { + // at this point, extra isn't content, so add padding + val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // at this point, extra isn't content nor padding, so add border + if ( extra !== "padding" ) { + val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + return val; +} + +function getWidthOrHeight( elem, name, extra ) { + + // Start with offset property, which is equivalent to the border-box value + var valueIsBorderBox = true, + val = name === "width" ? elem.offsetWidth : elem.offsetHeight, + styles = getStyles( elem ), + isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // some non-html elements return undefined for offsetWidth, so check for null/undefined + // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285 + // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668 + if ( val <= 0 || val == null ) { + // Fall back to computed then uncomputed css if necessary + val = curCSS( elem, name, styles ); + if ( val < 0 || val == null ) { + val = elem.style[ name ]; + } + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test(val) ) { + return val; + } + + // we need the check for style in case a browser which returns unreliable values + // for getComputedStyle silently falls back to the reliable elem.style + valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] ); + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + } + + // use the active box-sizing model to add/subtract irrelevant styles + return ( val + + augmentWidthOrHeight( + elem, + name, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles + ) + ) + "px"; +} + +// Try to determine the default display value of an element +function css_defaultDisplay( nodeName ) { + var doc = document, + display = elemdisplay[ nodeName ]; + + if ( !display ) { + display = actualDisplay( nodeName, doc ); + + // If the simple way fails, read from inside an iframe + if ( display === "none" || !display ) { + // Use the already-created iframe if possible + iframe = ( iframe || + jQuery("