diff --git a/.bowerrc b/.bowerrc deleted file mode 100644 index 25c9a0f..0000000 --- a/.bowerrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "directory": "vendor" -} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 7589f43..ad5b768 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,7 @@ node_modules/ *.log .build_cache~ build/*.map -vendor/ \ No newline at end of file +public/js/app.bundle.js +public/js/app.js +public/css/app.bundle.css +public/css/app.css \ No newline at end of file diff --git a/Gruntfile.coffee b/Gruntfile.coffee index 16eb291..1b335a3 100644 --- a/Gruntfile.coffee +++ b/Gruntfile.coffee @@ -27,42 +27,10 @@ module.exports = (grunt) -> dest: 'public/css/app.css' concat: - vendor: - src: [ - # Vendor dependencies. - 'vendor/lodash/dist/lodash.js' - 'vendor/ractive/ractive.js' - 'vendor/ractive-transitions-fade/ractive-transitions-fade.js' - 'vendor/ractive-ractive/index.js' - 'vendor/firebase/firebase.js' - 'vendor/superagent/superagent.js' - 'vendor/lscache/lscache.js' - 'vendor/async/lib/async.js' - 'vendor/moment/moment.js' - 'vendor/d3/d3.js' - 'vendor/d3-tip/index.js' - 'vendor/marked/lib/marked.js' - 'vendor/director/build/director.js' - 'vendor/sorted-index-compare/index.js' - 'node-semver/semver.js' - ] - dest: 'public/js/vendor.js' - options: - separator: ';' # for minification purposes - - bundle: - src: [ - 'public/js/vendor.min.js' - 'public/js/app.min.js' - ] - dest: 'public/js/app.bundle.min.js' - options: - separator: ';' # for minification purposes - css: src: [ # Vendor dependencies. - 'vendor/normalize-css/normalize.css' + 'node_modules/normalize.css/normalize.css' # Our style. 'public/css/app.css' ] @@ -71,8 +39,7 @@ module.exports = (grunt) -> uglify: bundle: files: - 'public/js/app.min.js': 'public/js/app.js' - 'public/js/vendor.min.js': 'public/js/vendor.js' + 'public/js/app.bundle.min.js': 'public/js/app.bundle.js' cssmin: bundle: @@ -90,7 +57,6 @@ module.exports = (grunt) -> # Stylus to CSS, concat JS libs and all CSS. grunt.registerTask('default', [ 'stylus:app' - 'concat:vendor' 'concat:css' ]) @@ -102,7 +68,6 @@ module.exports = (grunt) -> # Minify JS, CSS and concat JS. grunt.registerTask('minify', [ - 'uglify:bundle' - 'cssmin:bundle' - 'concat:bundle' + 'uglify' + 'cssmin' ]) \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2def0e8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 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 Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are 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. + + 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. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + 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 Affero 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. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + 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 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 work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero 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 Affero 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 Affero 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 Affero 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 Affero 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + 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 AGPL, see +. \ No newline at end of file diff --git a/Makefile b/Makefile index e31520f..e017c46 100644 --- a/Makefile +++ b/Makefile @@ -1,28 +1,29 @@ # Install dependencies. install: npm install - bower install - -# Build the app for production. -build-app: - ./node_modules/.bin/browserify -e ./src/app.coffee -o public/js/app.js # Watch the app sources and build with source maps. -watch-app: - ./node_modules/.bin/watchify -e ./src/app.coffee -o public/js/app.js -d -v - -# Build vendor libs and styles. -build-vendor: - grunt +watch: + ./node_modules/.bin/watchify -e ./src/app.coffee -o public/js/app.bundle.js -d -v # Serve locally. serve: cd public; python -m SimpleHTTPServer 8000 -# Make and publish a minified package. -publish: +# Make a minified package. +build: grunt init - make build-app - make build-vendor + ./node_modules/.bin/browserify -e ./src/app.coffee -o public/js/app.bundle.js + grunt grunt minify - firebase deploy \ No newline at end of file + +# Publish on Firebase or GitHub Pages. +publish: + # firebase deploy -> http://burnchart.firebaseapp.com + git subtree push --prefix public origin gh-pages + +# Run mocha test. +test: + ./node_modules/.bin/mocha --compilers coffee:coffee-script/register --reporter spec --ui exports --timeout 20000 --slow 15000 --bail + +.PHONY: test \ No newline at end of file diff --git a/README.md b/README.md index 14ee88f..9daa72e 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ -#burnchart.io +#burnchart -##Concept +GitHub Burndown Chart as a service. Answers the question "are my projects on track"? -GitHub Burndown Chart as a service. Answers the questions "are my projects on track"? +[![Build Status](http://img.shields.io/codeship/.svg?style=flat)]() +[![Dependencies](http://img.shields.io/david/radekstepan/burnchart.svg?style=flat)](https://david-dm.org/radekstepan/burnchart) +[![License](http://img.shields.io/badge/license-AGPL--3.0-red.svg?style=flat)](LICENSE) ##Notes diff --git a/bower.json b/bower.json deleted file mode 100644 index 841d3fc..0000000 --- a/bower.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "burnchart", - "version": "0.0.0", - "dependencies": { - "async": "~0.9.0", - "d3": "~3.4.11", - "d3-tip": "~0.6.5", - "director": "~1.2.2", - "firebase": "~1.1.2", - "lodash": "2.3.0", - "lscache": "~1.0.2", - "marked": "~0.3.2", - "moment": "~2.8.3", - "normalize-css": "2.1.3", - "ractive": "~0.6.0", - "ractive-ractive": "rstacruz/ractive-ractive", - "ractive-transitions-fade": "~0.1.2", - "sorted-index-compare": "6wunderkinder/sortedindex-compare", - "superagent": "~0.19.0", - "node-semver": "npm/node-semver#~4.1.0" - } -} diff --git a/docs/.gitkeep b/docs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/NOTES.md b/docs/NOTES.md similarity index 100% rename from NOTES.md rename to docs/NOTES.md diff --git a/TODO.md b/docs/TODO.md similarity index 96% rename from TODO.md rename to docs/TODO.md index d08767c..ffc19ee 100644 --- a/TODO.md +++ b/docs/TODO.md @@ -2,12 +2,15 @@ ##Release: Assembly +- [ ] when merged with github-burndown-chart use GitHub Hosting, add a publish script and use burnchart.io as a domain + ###Git - [ ] create notes about how original people can upgrade to burnchart -- [ ] add licensing, clean up docs, track them on git or using Assembly system? +- [ ] clean up docs, track them on git or using Assembly system? - [ ] rename repo to burnchart - [ ] check with austin@assembly.com if my repo looks good to be forked to Assembly +- [ ] move domain to Assembly - [ ] fork it to Assembly ###Error Handling diff --git a/package.json b/package.json index 30aafd8..984d6df 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,23 @@ "name": "burnchart", "version": "0.0.0", "description": "GitHub Burndown Chart as a Service", + "author": "Radek Stepan (http://radekstepan.com)", + "license": "AGPL-3.0", + "keywords": [ + "github", + "issues", + "burndown", + "chart", + "scrum" + ], + "repository": { + "type": "git", + "url": "git://github.com/radekstepan/burnchart.git" + }, + "scripts": { + "start": "make serve", + "test": "make test" + }, "devDependencies": { "grunt": "~0.4.1", "grunt-mkdir": "~0.1.2", @@ -13,20 +30,33 @@ "coffeeify": "~0.7.0L", "ractivate": "~0.2.0", "browserify": "~6.1.0", - "watchify": "~2.1.0" + "watchify": "~2.1.0", + + "mocha": "~2.0.1", + "coffee-script": "~1.8.0", + + "async": "~0.9.0", + "d3": "~3.4.13", + "d3-tip": "Caged/d3-tip", + "proxyquire": "~1.0.1", + "lodash": "~2.4.1", + "director": "~1.2.3", + "firebase": "~1.1.2", + "lscache": "~1.0.2", + "marked": "~0.3.2", + "moment": "~2.8.3", + "normalize.css": "~3.0.2", + "ractive": "~0.6.1", + "ractive-ractive": "~0.4.4", + "ractive-transitions-fade": "~0.1.2", + "sortedindex-compare": "0.0.1", + "superagent": "~0.20.0", + "semver": "~4.1.0" }, - "repository": { - "type": "git", - "url": "git://github.com/radekstepan/burnchart.io.git" - }, - "author": "Radek ", "browserify": { "transform": [ "coffeeify", "ractivate" ] - }, - "browser": { - "semver": "./vendor/node-semver/semver.js" } } diff --git a/public/css/app.bundle.css b/public/css/app.bundle.css index ac0a23a..1243568 100644 --- a/public/css/app.bundle.css +++ b/public/css/app.bundle.css @@ -1,11 +1,33 @@ -/*! normalize.css v2.1.3 | MIT License | git.io/normalize */ +/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ -/* ========================================================================== - HTML5 display definitions +/** + * 1. Set default font family to sans-serif. + * 2. Prevent iOS text size adjust after orientation change, without disabling + * user zoom. + */ + +html { + font-family: sans-serif; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/** + * Remove default margin. + */ + +body { + margin: 0; +} + +/* HTML5 display definitions ========================================================================== */ /** - * Correct `block` display not defined in IE 8/9. + * Correct `block` display not defined for any HTML5 element in IE 8/9. + * Correct `block` display not defined for `details` or `summary` in IE 10/11 + * and Firefox. + * Correct `block` display not defined for `main` in IE 11. */ article, @@ -17,20 +39,24 @@ footer, header, hgroup, main, +menu, nav, section, summary { - display: block; + display: block; } /** - * Correct `inline-block` display not defined in IE 8/9. + * 1. Correct `inline-block` display not defined in IE 8/9. + * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. */ audio, canvas, +progress, video { - display: inline-block; + display: inline-block; /* 1 */ + vertical-align: baseline; /* 2 */ } /** @@ -39,46 +65,21 @@ video { */ audio:not([controls]) { - display: none; - height: 0; + display: none; + height: 0; } /** - * Address `[hidden]` styling not present in IE 8/9. - * Hide the `template` element in IE, Safari, and Firefox < 22. + * Address `[hidden]` styling not present in IE 8/9/10. + * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. */ [hidden], template { - display: none; + display: none; } -/* ========================================================================== - Base - ========================================================================== */ - -/** - * 1. Set default font family to sans-serif. - * 2. Prevent iOS text size adjust after orientation change, without disabling - * user zoom. - */ - -html { - font-family: sans-serif; /* 1 */ - -ms-text-size-adjust: 100%; /* 2 */ - -webkit-text-size-adjust: 100%; /* 2 */ -} - -/** - * Remove default margin. - */ - -body { - margin: 0; -} - -/* ========================================================================== - Links +/* Links ========================================================================== */ /** @@ -86,15 +87,7 @@ body { */ a { - background: transparent; -} - -/** - * Address `outline` inconsistency between Chrome and other browsers. - */ - -a:focus { - outline: thin dotted; + background-color: transparent; } /** @@ -103,56 +96,45 @@ a:focus { a:active, a:hover { - outline: 0; + outline: 0; } -/* ========================================================================== - Typography +/* Text-level semantics ========================================================================== */ /** - * Address variable `h1` font-size and margin within `section` and `article` - * contexts in Firefox 4+, Safari 5, and Chrome. - */ - -h1 { - font-size: 2em; - margin: 0.67em 0; -} - -/** - * Address styling not present in IE 8/9, Safari 5, and Chrome. + * Address styling not present in IE 8/9/10/11, Safari, and Chrome. */ abbr[title] { - border-bottom: 1px dotted; + border-bottom: 1px dotted; } /** - * Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome. + * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. */ b, strong { - font-weight: bold; + font-weight: bold; } /** - * Address styling not present in Safari 5 and Chrome. + * Address styling not present in Safari and Chrome. */ dfn { - font-style: italic; + font-style: italic; } /** - * Address differences between Firefox and other browsers. + * Address variable `h1` font-size and margin within `section` and `article` + * contexts in Firefox 4+, Safari, and Chrome. */ -hr { - -moz-box-sizing: content-box; - box-sizing: content-box; - height: 0; +h1 { + font-size: 2em; + margin: 0.67em 0; } /** @@ -160,36 +142,8 @@ hr { */ mark { - background: #ff0; - color: #000; -} - -/** - * Correct font family set oddly in Safari 5 and Chrome. - */ - -code, -kbd, -pre, -samp { - font-family: monospace, serif; - font-size: 1em; -} - -/** - * Improve readability of pre-formatted text in all browsers. - */ - -pre { - white-space: pre-wrap; -} - -/** - * Set consistent quote types. - */ - -q { - quotes: "\201C" "\201D" "\2018" "\2019"; + background: #ff0; + color: #000; } /** @@ -197,7 +151,7 @@ q { */ small { - font-size: 80%; + font-size: 80%; } /** @@ -206,111 +160,123 @@ small { sub, sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; } sup { - top: -0.5em; + top: -0.5em; } sub { - bottom: -0.25em; + bottom: -0.25em; } -/* ========================================================================== - Embedded content +/* Embedded content ========================================================================== */ /** - * Remove border when inside `a` element in IE 8/9. + * Remove border when inside `a` element in IE 8/9/10. */ img { - border: 0; + border: 0; } /** - * Correct overflow displayed oddly in IE 9. + * Correct overflow not hidden in IE 9/10/11. */ svg:not(:root) { - overflow: hidden; + overflow: hidden; } -/* ========================================================================== - Figures +/* Grouping content ========================================================================== */ /** - * Address margin not present in IE 8/9 and Safari 5. + * Address margin not present in IE 8/9 and Safari. */ figure { - margin: 0; + margin: 1em 40px; } -/* ========================================================================== - Forms +/** + * Address differences between Firefox and other browsers. + */ + +hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; +} + +/** + * Contain overflow in all browsers. + */ + +pre { + overflow: auto; +} + +/** + * Address odd `em`-unit font size rendering in all browsers. + */ + +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} + +/* Forms ========================================================================== */ /** - * Define consistent border, margin, and padding. + * Known limitation: by default, Chrome and Safari on OS X allow very limited + * styling of `select`, unless a `border` property is set. */ -fieldset { - border: 1px solid #c0c0c0; - margin: 0 2px; - padding: 0.35em 0.625em 0.75em; -} - /** - * 1. Correct `color` not being inherited in IE 8/9. - * 2. Remove padding so people aren't caught out if they zero out fieldsets. - */ - -legend { - border: 0; /* 1 */ - padding: 0; /* 2 */ -} - -/** - * 1. Correct font family not being inherited in all browsers. - * 2. Correct font size not being inherited in all browsers. - * 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome. + * 1. Correct color not being inherited. + * Known issue: affects color of disabled elements. + * 2. Correct font properties not being inherited. + * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. */ button, input, +optgroup, select, textarea { - font-family: inherit; /* 1 */ - font-size: 100%; /* 2 */ - margin: 0; /* 3 */ + color: inherit; /* 1 */ + font: inherit; /* 2 */ + margin: 0; /* 3 */ } /** - * Address Firefox 4+ setting `line-height` on `input` using `!important` in - * the UA stylesheet. + * Address `overflow` set to `hidden` in IE 8/9/10/11. */ -button, -input { - line-height: normal; +button { + overflow: visible; } /** * Address inconsistent `text-transform` inheritance for `button` and `select`. * All other form control elements do not inherit `text-transform` values. - * Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+. - * Correct `select` style inheritance in Firefox 4+ and Opera. + * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. + * Correct `select` style inheritance in Firefox. */ button, select { - text-transform: none; + text-transform: none; } /** @@ -325,8 +291,8 @@ button, html input[type="button"], /* 1 */ input[type="reset"], input[type="submit"] { - -webkit-appearance: button; /* 2 */ - cursor: pointer; /* 3 */ + -webkit-appearance: button; /* 2 */ + cursor: pointer; /* 3 */ } /** @@ -335,41 +301,7 @@ input[type="submit"] { button[disabled], html input[disabled] { - cursor: default; -} - -/** - * 1. Address box sizing set to `content-box` in IE 8/9/10. - * 2. Remove excess padding in IE 8/9/10. - */ - -input[type="checkbox"], -input[type="radio"] { - box-sizing: border-box; /* 1 */ - padding: 0; /* 2 */ -} - -/** - * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. - * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome - * (include `-moz` to future-proof). - */ - -input[type="search"] { - -webkit-appearance: textfield; /* 1 */ - -moz-box-sizing: content-box; - -webkit-box-sizing: content-box; /* 2 */ - box-sizing: content-box; -} - -/** - * Remove inner padding and search cancel button in Safari 5 and Chrome - * on OS X. - */ - -input[type="search"]::-webkit-search-cancel-button, -input[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; + cursor: default; } /** @@ -378,22 +310,106 @@ input[type="search"]::-webkit-search-decoration { button::-moz-focus-inner, input::-moz-focus-inner { - border: 0; - padding: 0; + border: 0; + padding: 0; } /** - * 1. Remove default vertical scrollbar in IE 8/9. - * 2. Improve readability and alignment in all browsers. + * Address Firefox 4+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ + +input { + line-height: normal; +} + +/** + * It's recommended that you don't attempt to style these elements. + * Firefox's implementation doesn't respect box-sizing, padding, or width. + * + * 1. Address box sizing set to `content-box` in IE 8/9/10. + * 2. Remove excess padding in IE 8/9/10. + */ + +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Fix the cursor style for Chrome's increment/decrement buttons. For certain + * `font-size` values of the `input`, it causes the cursor style of the + * decrement button to change from `default` to `text`. + */ + +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Address `appearance` set to `searchfield` in Safari and Chrome. + * 2. Address `box-sizing` set to `border-box` in Safari and Chrome + * (include `-moz` to future-proof). + */ + +input[type="search"] { + -webkit-appearance: textfield; /* 1 */ + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; /* 2 */ + box-sizing: content-box; +} + +/** + * Remove inner padding and search cancel button in Safari and Chrome on OS X. + * Safari (but not Chrome) clips the cancel button when the search input has + * padding (and `textfield` appearance). + */ + +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * Define consistent border, margin, and padding. + */ + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/** + * 1. Correct `color` not being inherited in IE 8/9/10/11. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ + +legend { + border: 0; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Remove default vertical scrollbar in IE 8/9/10/11. */ textarea { - overflow: auto; /* 1 */ - vertical-align: top; /* 2 */ + overflow: auto; } -/* ========================================================================== - Tables +/** + * Don't inherit the `font-weight` (applied by a rule above). + * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. + */ + +optgroup { + font-weight: bold; +} + +/* Tables ========================================================================== */ /** @@ -401,8 +417,13 @@ textarea { */ table { - border-collapse: collapse; - border-spacing: 0; + border-collapse: collapse; + border-spacing: 0; +} + +td, +th { + padding: 0; } @font-face{font-family:'MuseoSlab500Regular';src:url("../fonts/museo-slab-500.eot");src:url("../fonts/museo-slab-500.eot?#iefix") format('embedded-opentype'),url("../fonts/museo-slab-500.woff") format('woff'),url("../fonts/museo-slab-500.ttf") format('truetype'),url("../fonts/museo-slab-500.svg#MuseoSlab500Regular") format('svg');font-weight:normal;font-style:normal} diff --git a/public/css/app.bundle.min.css b/public/css/app.bundle.min.css index 75789a6..6c21050 100644 --- a/public/css/app.bundle.min.css +++ b/public/css/app.bundle.min.css @@ -1 +1 @@ -/*! normalize.css v2.1.3 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}a{background:0 0}a:focus{outline:dotted thin}a:active,a:hover{outline:0}h1{font-size:2em}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}mark{background:#ff0;color:#000}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}button,input{line-height:normal}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}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}@font-face{font-family:MuseoSlab500Regular;src:url(../fonts/museo-slab-500.eot);src:url(../fonts/museo-slab-500.eot?#iefix) format('embedded-opentype'),url(../fonts/museo-slab-500.woff) format('woff'),url(../fonts/museo-slab-500.ttf) format('truetype'),url(../fonts/museo-slab-500.svg#MuseoSlab500Regular) format('svg');font-weight:400;font-style:normal}@font-face{font-family:MuseoSans500Regular;src:url(../fonts/museo-sans-500.eot);src:url(../fonts/museo-sans-500.eot?#iefix) format('embedded-opentype'),url(../fonts/museo-sans-500.woff) format('woff'),url(../fonts/museo-sans-500.ttf) format('truetype'),url(../fonts/museo-sans-500.svg#MuseoSans500Regular) format('svg');font-weight:400;font-style:normal}@font-face{font-family:Fontello;src:url(../fonts/fontello.eot?74672344);src:url(../fonts/fontello.eot?74672344#iefix) format('embedded-opentype'),url(../fonts/fontello.woff?74672344) format('woff'),url(../fonts/fontello.ttf?74672344) format('truetype'),url(../fonts/fontello.svg?74672344#fontello) format('svg');font-weight:400;font-style:normal}.icon{vertical-align:middle;font-family:Fontello;font-style:normal;font-weight:400;speak:none;display:inline-block;text-decoration:inherit;text-align:center;font-variant:normal;text-transform:none}.icon[class*=' spin'],.icon[class^=spin]{-webkit-animation:spin 2s infinite linear;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;-ms-animation:spin 2s infinite linear;animation:spin 2s infinite linear}@-moz-keyframes spin{0%{-moz-transform:rotate(0)}100%{-moz-transform:rotate(360deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0)}100%{-webkit-transform:rotate(360deg)}}@-moz-keyframes spin{0%{-webkit-transform:rotate(0);-moz-transform:rotate(0);-o-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-o-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0);-moz-transform:rotate(0);-o-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-o-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-o-keyframes spin{0%{-webkit-transform:rotate(0);-moz-transform:rotate(0);-o-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-o-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes spin{0%{-webkit-transform:rotate(0);-moz-transform:rotate(0);-o-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-o-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes spin{0%{-webkit-transform:rotate(0);-moz-transform:rotate(0);-o-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-o-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}#chart{height:300px;position:relative}#chart #tooltip{position:absolute;top:0;left:0}#chart svg path.line{fill:none;stroke-width:1px;clip-path:url(#clip)}#chart svg path.line.actual{stroke:#64584c;stroke-width:3px}#chart svg path.line.ideal{stroke:#cacaca;stroke-width:3px}#chart svg path.line.trendline{stroke:#64584c;stroke-width:1.5px;stroke-dasharray:5,5}#chart svg line.today{stroke:#cacaca;stroke-width:1px;shape-rendering:crispEdges;stroke-dasharray:5,5}#chart svg circle{fill:#64584c;stroke:transparent;stroke-width:15px;cursor:pointer}#chart svg .axis{shape-rendering:crispEdges}#chart svg .axis line{stroke:rgba(202,202,202,.25);shape-rendering:crispEdges}#chart svg .axis text{font-weight:700;fill:#cacaca}#chart svg .axis path{display:none}.d3-tip{margin-top:-10px;font-size:11px;padding:8px 10px 7px;text-align:center;background:rgba(0,0,0,.75);color:#fff;-webkit-border-radius:3px;border-radius:3px}.d3-tip:after{width:100%;color:rgba(0,0,0,.8);content:"\25BC";position:absolute}.d3-tip.n:after{margin:-3px 0 0;top:100%;left:0}body,html{margin:0;padding:0;height:100%}body{color:#3e4457;font-family:MuseoSans500Regular,sans-serif}#app{position:relative;height:auto!important;min-height:100%}a{text-decoration:none;color:#aaafbf;cursor:pointer}h1,h2,h3,p{margin:0}ul{list-style-type:none;margin:0;padding:0}ul li{display:inline-block}.wrap{width:800px;margin:0 auto}#notify{position:fixed;top:-68px;z-index:1;width:100%;background:#fcfcfc;color:#aaafbf;border-top:3px solid #aaafbf;border-bottom:1px solid #f3f4f8}#notify .close{float:right;font-size:16px;padding:22px;cursor:pointer}#notify .close:before{content:"\d7";display:block}#notify.system{top:0;left:50%;-webkit-transform:translateX(-50%) translateY(-50%);-moz-transform:translateX(-50%) translateY(-50%);-o-transform:translateX(-50%) translateY(-50%);-ms-transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%);width:500px}#notify.system p{padding-top:20px}#notify.good,#notify.ok,#notify.success{border-top-color:#00b361;color:#00b361}#notify.trouble,#notify.warn{border-top-color:#ea9712;color:#ea9712}#notify.alert,#notify.bad,#notify.fucked{border-top-color:#c1041c;color:#c1041c}#notify .icon,#notify p{display:block}#notify .icon{font-size:26px;padding:18px;width:38px;float:left}#notify p{padding:22px 20px 20px 74px;text-align:justify}#head{background:#c1041c;height:64px}#head #icon{font-size:26px;padding:10px 0;line-height:44px;height:44px;width:74px;background:#77000e;display:inline-block;color:#c1041c;margin:0;text-align:center}#head .q{position:relative;display:inline-block;margin:13px 20px 0;vertical-align:top}#head .q .icon{position:absolute;color:#c1041c}#head .q .icon.search{top:8px;left:12px}#head .q .icon.down-open{top:8px;right:12px}#head .q input{background:#77000e;border:0;padding:10px 12px 10px 36px;font-size:14px;-webkit-border-radius:2px;border-radius:2px;color:#fff;width:220px}#head ul{display:inline-block}#head ul li{margin-left:30px}#head a{color:#e0808d;font-weight:700}#head a.active,#head a:hover{color:#fff}#head .right{float:right;margin-right:20px;line-height:64px;color:#e0808d}#head .right a{-webkit-border-radius:2px;border-radius:2px;background:#ffbb2a;color:#c1041c;padding:11px 20px}#title{border-bottom:3px solid #f3f4f8}#title .title{border-bottom:3px solid #aaafbf;margin:30px 0 -3px;display:inline-block;padding-bottom:20px}#title .sub{font-size:16px;font-weight:700;margin:0 20px}#title .description{display:inline-block;font-family:MuseoSlab500Regular,serif;white-space:nowrap;color:#b1b6c4}#page{padding-bottom:80px}#page #content{padding:20px;margin-top:20px;margin-bottom:40px}#page #content #hero{background:url(../img/hires/2.jpg) center/cover;-webkit-background-size:cover;-moz-background-size:cover;-webkit-border-radius:2px;border-radius:2px;margin-bottom:30px}#page #content #hero .content{-webkit-border-radius:2px;border-radius:2px;color:#fff;padding:30px;background:rgba(0,0,0,.3);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.2);box-shadow:inset 0 1px 2px rgba(0,0,0,.2)}#page #content #hero .content h2{margin-bottom:20px;margin-left:140px}#page #content #hero .content p{font-family:MuseoSlab500Regular,serif;font-size:18px;line-height:24px;margin-left:140px;text-align:justify;text-justify:inter-word}#page #content #hero .content .address{font-size:120px;float:left}#page #content #hero .content .cta{text-align:center;margin-top:10px}#page #content #hero .content .cta a{font-family:MuseoSlab500Regular,serif;padding:11px 20px;-webkit-border-radius:2px;border-radius:2px;display:inline-block;margin:0 4px}#page #content #hero .content .cta a.primary{font-weight:700;background:#c1041c;color:#fff}#page #content #hero .content .cta a.secondary{background:#fff;color:#c1041c}#page #content #add h2{color:#3e4457}#page #content #add p{font-family:MuseoSlab500Regular,serif;color:#b1b6c4;margin-top:10px;line-height:20px;text-align:justify;text-justify:inter-word}#page #content #add p a{color:#3e4457}#page #content #add .form{margin-top:20px}#page #content #add .form table,#page #content #add .form table tr td:first-child{width:100%}#page #content #add .form input{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:10px;width:100%;-webkit-border-radius:2px 0 0 2px;border-radius:2px 0 0 2px;border:1px solid #dde1ed;border-right:0;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.2);box-shadow:inset 0 1px 2px rgba(0,0,0,.2)}#page #content #add .form a{margin-left:-2px;font-family:MuseoSlab500Regular,serif;padding:11px 20px;-webkit-border-radius:0 2px 2px 0;border-radius:0 2px 2px 0;display:inline-block;font-weight:700;background:#c1041c;color:#fff}#page #content #projects{border:1px solid #cdcecf;-webkit-border-radius:2px;border-radius:2px}#page #content #projects h2{color:#3e4457;display:inline-block}#page #content #projects .sort{float:right;line-height:30px}#page #content #projects table{width:100%}#page #content #projects table tr td{background:#fcfcfc;padding:20px 30px;border-bottom:1px solid #eaecf2}#page #content #projects table tr td .project{color:inherit}#page #content #projects table tr td .project .error{cursor:help;color:#c1041c}#page #content #projects table tr td a.project{font-weight:700}#page #content #projects table tr td .milestone .icon{font-size:10px;margin:0}#page #content #projects table tr td .progress{width:200px}#page #content #projects table tr td .progress .due,#page #content #projects table tr td .progress .percent{color:#9399ad;font-size:13px}#page #content #projects table tr td .progress .percent{float:right}#page #content #projects table tr td .progress .bar{-webkit-border-radius:4px;border-radius:4px;background:#eaecf2;height:10px;width:100%}#page #content #projects table tr td .progress .bar.inner{-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.2);box-shadow:inset 0 1px 2px rgba(0,0,0,.2)}#page #content #projects table tr td .progress .bar.red{background:#c1041c}#page #content #projects table tr td .progress .bar.green{background:#00b361}#page #content #projects table tr td .progress .due.red{color:#c1041c;font-weight:700}#page #content #projects table tr td:first-child{color:#3e4457}#page #content #projects table tr:nth-child(even) td{background:#fefefe}#page #content #projects table tr:last-child td{border:0}#page #content #projects table tr.done td{background:#ebf6f1}#page #content #projects table tr.done td .due,#page #content #projects table tr.done td .milestone,#page #content #projects table tr.done td .percent{color:#00b361}#page #content #projects .footer,#page #content #projects .header{padding:20px 30px}#page #content #projects .header{-webkit-box-shadow:0 1px 2px rgba(221,225,237,.5);box-shadow:0 1px 2px rgba(221,225,237,.5);margin-bottom:2px;border-bottom:1px solid #dde1ed}#page #content #projects .header a{font-family:MuseoSlab500Regular,serif}#page #content #projects .footer{background:#f9fafb;color:#aaafbf;-webkit-box-shadow:inset 0 1px 2px rgba(221,225,237,.2);box-shadow:inset 0 1px 2px rgba(221,225,237,.2);border-top:1px solid #dde1ed;text-align:right;font-family:MuseoSlab500Regular,serif}#page #content #projects .footer .icon{color:#aaafbf}#footer{position:absolute;width:100%;bottom:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;border-top:1px solid #f3f4f8;text-align:center;padding:30px;font-family:MuseoSlab500Regular,serif} \ No newline at end of file +/*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}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:700}dfn{font-style:italic}h1{font-size:2em}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}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{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{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-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}@font-face{font-family:MuseoSlab500Regular;src:url(../fonts/museo-slab-500.eot);src:url(../fonts/museo-slab-500.eot?#iefix) format('embedded-opentype'),url(../fonts/museo-slab-500.woff) format('woff'),url(../fonts/museo-slab-500.ttf) format('truetype'),url(../fonts/museo-slab-500.svg#MuseoSlab500Regular) format('svg');font-weight:400;font-style:normal}@font-face{font-family:MuseoSans500Regular;src:url(../fonts/museo-sans-500.eot);src:url(../fonts/museo-sans-500.eot?#iefix) format('embedded-opentype'),url(../fonts/museo-sans-500.woff) format('woff'),url(../fonts/museo-sans-500.ttf) format('truetype'),url(../fonts/museo-sans-500.svg#MuseoSans500Regular) format('svg');font-weight:400;font-style:normal}@font-face{font-family:Fontello;src:url(../fonts/fontello.eot?74672344);src:url(../fonts/fontello.eot?74672344#iefix) format('embedded-opentype'),url(../fonts/fontello.woff?74672344) format('woff'),url(../fonts/fontello.ttf?74672344) format('truetype'),url(../fonts/fontello.svg?74672344#fontello) format('svg');font-weight:400;font-style:normal}.icon{vertical-align:middle;font-family:Fontello;font-style:normal;font-weight:400;speak:none;display:inline-block;text-decoration:inherit;text-align:center;font-variant:normal;text-transform:none}.icon[class*=' spin'],.icon[class^=spin]{-webkit-animation:spin 2s infinite linear;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;-ms-animation:spin 2s infinite linear;animation:spin 2s infinite linear}@-moz-keyframes spin{0%{-moz-transform:rotate(0)}100%{-moz-transform:rotate(360deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0)}100%{-webkit-transform:rotate(360deg)}}@-moz-keyframes spin{0%{-webkit-transform:rotate(0);-moz-transform:rotate(0);-o-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-o-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0);-moz-transform:rotate(0);-o-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-o-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-o-keyframes spin{0%{-webkit-transform:rotate(0);-moz-transform:rotate(0);-o-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-o-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes spin{0%{-webkit-transform:rotate(0);-moz-transform:rotate(0);-o-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-o-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes spin{0%{-webkit-transform:rotate(0);-moz-transform:rotate(0);-o-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-o-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg)}}#chart{height:300px;position:relative}#chart #tooltip{position:absolute;top:0;left:0}#chart svg path.line{fill:none;stroke-width:1px;clip-path:url(#clip)}#chart svg path.line.actual{stroke:#64584c;stroke-width:3px}#chart svg path.line.ideal{stroke:#cacaca;stroke-width:3px}#chart svg path.line.trendline{stroke:#64584c;stroke-width:1.5px;stroke-dasharray:5,5}#chart svg line.today{stroke:#cacaca;stroke-width:1px;shape-rendering:crispEdges;stroke-dasharray:5,5}#chart svg circle{fill:#64584c;stroke:transparent;stroke-width:15px;cursor:pointer}#chart svg .axis{shape-rendering:crispEdges}#chart svg .axis line{stroke:rgba(202,202,202,.25);shape-rendering:crispEdges}#chart svg .axis text{font-weight:700;fill:#cacaca}#chart svg .axis path{display:none}.d3-tip{margin-top:-10px;font-size:11px;padding:8px 10px 7px;text-align:center;background:rgba(0,0,0,.75);color:#fff;-webkit-border-radius:3px;border-radius:3px}.d3-tip:after{width:100%;color:rgba(0,0,0,.8);content:"\25BC";position:absolute}.d3-tip.n:after{margin:-3px 0 0;top:100%;left:0}body,html{margin:0;padding:0;height:100%}body{color:#3e4457;font-family:MuseoSans500Regular,sans-serif}#app{position:relative;height:auto!important;min-height:100%}a{text-decoration:none;color:#aaafbf;cursor:pointer}h1,h2,h3,p{margin:0}ul{list-style-type:none;margin:0;padding:0}ul li{display:inline-block}.wrap{width:800px;margin:0 auto}#notify{position:fixed;top:-68px;z-index:1;width:100%;background:#fcfcfc;color:#aaafbf;border-top:3px solid #aaafbf;border-bottom:1px solid #f3f4f8}#notify .close{float:right;font-size:16px;padding:22px;cursor:pointer}#notify .close:before{content:"\d7";display:block}#notify.system{top:0;left:50%;-webkit-transform:translateX(-50%) translateY(-50%);-moz-transform:translateX(-50%) translateY(-50%);-o-transform:translateX(-50%) translateY(-50%);-ms-transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%);width:500px}#notify.system p{padding-top:20px}#notify.good,#notify.ok,#notify.success{border-top-color:#00b361;color:#00b361}#notify.trouble,#notify.warn{border-top-color:#ea9712;color:#ea9712}#notify.alert,#notify.bad,#notify.fucked{border-top-color:#c1041c;color:#c1041c}#notify .icon,#notify p{display:block}#notify .icon{font-size:26px;padding:18px;width:38px;float:left}#notify p{padding:22px 20px 20px 74px;text-align:justify}#head{background:#c1041c;height:64px}#head #icon{font-size:26px;padding:10px 0;line-height:44px;height:44px;width:74px;background:#77000e;display:inline-block;color:#c1041c;margin:0;text-align:center}#head .q{position:relative;display:inline-block;margin:13px 20px 0;vertical-align:top}#head .q .icon{position:absolute;color:#c1041c}#head .q .icon.search{top:8px;left:12px}#head .q .icon.down-open{top:8px;right:12px}#head .q input{background:#77000e;border:0;padding:10px 12px 10px 36px;font-size:14px;-webkit-border-radius:2px;border-radius:2px;color:#fff;width:220px}#head ul{display:inline-block}#head ul li{margin-left:30px}#head a{color:#e0808d;font-weight:700}#head a.active,#head a:hover{color:#fff}#head .right{float:right;margin-right:20px;line-height:64px;color:#e0808d}#head .right a{-webkit-border-radius:2px;border-radius:2px;background:#ffbb2a;color:#c1041c;padding:11px 20px}#title{border-bottom:3px solid #f3f4f8}#title .title{border-bottom:3px solid #aaafbf;margin:30px 0 -3px;display:inline-block;padding-bottom:20px}#title .sub{font-size:16px;font-weight:700;margin:0 20px}#title .description{display:inline-block;font-family:MuseoSlab500Regular,serif;white-space:nowrap;color:#b1b6c4}#page{padding-bottom:80px}#page #content{padding:20px;margin-top:20px;margin-bottom:40px}#page #content #hero{background:url(../img/hires/2.jpg) center/cover;-webkit-background-size:cover;-moz-background-size:cover;-webkit-border-radius:2px;border-radius:2px;margin-bottom:30px}#page #content #hero .content{-webkit-border-radius:2px;border-radius:2px;color:#fff;padding:30px;background:rgba(0,0,0,.3);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.2);box-shadow:inset 0 1px 2px rgba(0,0,0,.2)}#page #content #hero .content h2{margin-bottom:20px;margin-left:140px}#page #content #hero .content p{font-family:MuseoSlab500Regular,serif;font-size:18px;line-height:24px;margin-left:140px;text-align:justify;text-justify:inter-word}#page #content #hero .content .address{font-size:120px;float:left}#page #content #hero .content .cta{text-align:center;margin-top:10px}#page #content #hero .content .cta a{font-family:MuseoSlab500Regular,serif;padding:11px 20px;-webkit-border-radius:2px;border-radius:2px;display:inline-block;margin:0 4px}#page #content #hero .content .cta a.primary{font-weight:700;background:#c1041c;color:#fff}#page #content #hero .content .cta a.secondary{background:#fff;color:#c1041c}#page #content #add h2{color:#3e4457}#page #content #add p{font-family:MuseoSlab500Regular,serif;color:#b1b6c4;margin-top:10px;line-height:20px;text-align:justify;text-justify:inter-word}#page #content #add p a{color:#3e4457}#page #content #add .form{margin-top:20px}#page #content #add .form table,#page #content #add .form table tr td:first-child{width:100%}#page #content #add .form input{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:10px;width:100%;-webkit-border-radius:2px 0 0 2px;border-radius:2px 0 0 2px;border:1px solid #dde1ed;border-right:0;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.2);box-shadow:inset 0 1px 2px rgba(0,0,0,.2)}#page #content #add .form a{margin-left:-2px;font-family:MuseoSlab500Regular,serif;padding:11px 20px;-webkit-border-radius:0 2px 2px 0;border-radius:0 2px 2px 0;display:inline-block;font-weight:700;background:#c1041c;color:#fff}#page #content #projects{border:1px solid #cdcecf;-webkit-border-radius:2px;border-radius:2px}#page #content #projects h2{color:#3e4457;display:inline-block}#page #content #projects .sort{float:right;line-height:30px}#page #content #projects table{width:100%}#page #content #projects table tr td{background:#fcfcfc;padding:20px 30px;border-bottom:1px solid #eaecf2}#page #content #projects table tr td .project{color:inherit}#page #content #projects table tr td .project .error{cursor:help;color:#c1041c}#page #content #projects table tr td a.project{font-weight:700}#page #content #projects table tr td .milestone .icon{font-size:10px;margin:0}#page #content #projects table tr td .progress{width:200px}#page #content #projects table tr td .progress .due,#page #content #projects table tr td .progress .percent{color:#9399ad;font-size:13px}#page #content #projects table tr td .progress .percent{float:right}#page #content #projects table tr td .progress .bar{-webkit-border-radius:4px;border-radius:4px;background:#eaecf2;height:10px;width:100%}#page #content #projects table tr td .progress .bar.inner{-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.2);box-shadow:inset 0 1px 2px rgba(0,0,0,.2)}#page #content #projects table tr td .progress .bar.red{background:#c1041c}#page #content #projects table tr td .progress .bar.green{background:#00b361}#page #content #projects table tr td .progress .due.red{color:#c1041c;font-weight:700}#page #content #projects table tr td:first-child{color:#3e4457}#page #content #projects table tr:nth-child(even) td{background:#fefefe}#page #content #projects table tr:last-child td{border:0}#page #content #projects table tr.done td{background:#ebf6f1}#page #content #projects table tr.done td .due,#page #content #projects table tr.done td .milestone,#page #content #projects table tr.done td .percent{color:#00b361}#page #content #projects .footer,#page #content #projects .header{padding:20px 30px}#page #content #projects .header{-webkit-box-shadow:0 1px 2px rgba(221,225,237,.5);box-shadow:0 1px 2px rgba(221,225,237,.5);margin-bottom:2px;border-bottom:1px solid #dde1ed}#page #content #projects .header a{font-family:MuseoSlab500Regular,serif}#page #content #projects .footer{background:#f9fafb;color:#aaafbf;-webkit-box-shadow:inset 0 1px 2px rgba(221,225,237,.2);box-shadow:inset 0 1px 2px rgba(221,225,237,.2);border-top:1px solid #dde1ed;text-align:right;font-family:MuseoSlab500Regular,serif}#page #content #projects .footer .icon{color:#aaafbf}#footer{position:absolute;width:100%;bottom:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;border-top:1px solid #f3f4f8;text-align:center;padding:30px;font-family:MuseoSlab500Regular,serif} \ No newline at end of file diff --git a/public/index-dev.html b/public/index-dev.html index 4a25c27..6fc399e 100644 --- a/public/index-dev.html +++ b/public/index-dev.html @@ -5,7 +5,6 @@ - - + \ No newline at end of file diff --git a/public/js/app.bundle.js b/public/js/app.bundle.js new file mode 100644 index 0000000..eab6322 --- /dev/null +++ b/public/js/app.bundle.js @@ -0,0 +1,41819 @@ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= arr.length) { + callback(); + } + } + } + }; + async.forEach = async.each; + + async.eachSeries = function (arr, iterator, callback) { + callback = callback || function () {}; + if (!arr.length) { + return callback(); + } + var completed = 0; + var iterate = function () { + iterator(arr[completed], function (err) { + if (err) { + callback(err); + callback = function () {}; + } + else { + completed += 1; + if (completed >= arr.length) { + callback(); + } + else { + iterate(); + } + } + }); + }; + iterate(); + }; + async.forEachSeries = async.eachSeries; + + async.eachLimit = function (arr, limit, iterator, callback) { + var fn = _eachLimit(limit); + fn.apply(null, [arr, iterator, callback]); + }; + async.forEachLimit = async.eachLimit; + + var _eachLimit = function (limit) { + + return function (arr, iterator, callback) { + callback = callback || function () {}; + if (!arr.length || limit <= 0) { + return callback(); + } + var completed = 0; + var started = 0; + var running = 0; + + (function replenish () { + if (completed >= arr.length) { + return callback(); + } + + while (running < limit && started < arr.length) { + started += 1; + running += 1; + iterator(arr[started - 1], function (err) { + if (err) { + callback(err); + callback = function () {}; + } + else { + completed += 1; + running -= 1; + if (completed >= arr.length) { + callback(); + } + else { + replenish(); + } + } + }); + } + })(); + }; + }; + + + var doParallel = function (fn) { + return function () { + var args = Array.prototype.slice.call(arguments); + return fn.apply(null, [async.each].concat(args)); + }; + }; + var doParallelLimit = function(limit, fn) { + return function () { + var args = Array.prototype.slice.call(arguments); + return fn.apply(null, [_eachLimit(limit)].concat(args)); + }; + }; + var doSeries = function (fn) { + return function () { + var args = Array.prototype.slice.call(arguments); + return fn.apply(null, [async.eachSeries].concat(args)); + }; + }; + + + var _asyncMap = function (eachfn, arr, iterator, callback) { + arr = _map(arr, function (x, i) { + return {index: i, value: x}; + }); + if (!callback) { + eachfn(arr, function (x, callback) { + iterator(x.value, function (err) { + callback(err); + }); + }); + } else { + var results = []; + eachfn(arr, function (x, callback) { + iterator(x.value, function (err, v) { + results[x.index] = v; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + } + }; + async.map = doParallel(_asyncMap); + async.mapSeries = doSeries(_asyncMap); + async.mapLimit = function (arr, limit, iterator, callback) { + return _mapLimit(limit)(arr, iterator, callback); + }; + + var _mapLimit = function(limit) { + return doParallelLimit(limit, _asyncMap); + }; + + // reduce only has a series version, as doing reduce in parallel won't + // work in many situations. + async.reduce = function (arr, memo, iterator, callback) { + async.eachSeries(arr, function (x, callback) { + iterator(memo, x, function (err, v) { + memo = v; + callback(err); + }); + }, function (err) { + callback(err, memo); + }); + }; + // inject alias + async.inject = async.reduce; + // foldl alias + async.foldl = async.reduce; + + async.reduceRight = function (arr, memo, iterator, callback) { + var reversed = _map(arr, function (x) { + return x; + }).reverse(); + async.reduce(reversed, memo, iterator, callback); + }; + // foldr alias + async.foldr = async.reduceRight; + + var _filter = function (eachfn, arr, iterator, callback) { + var results = []; + arr = _map(arr, function (x, i) { + return {index: i, value: x}; + }); + eachfn(arr, function (x, callback) { + iterator(x.value, function (v) { + if (v) { + results.push(x); + } + callback(); + }); + }, function (err) { + callback(_map(results.sort(function (a, b) { + return a.index - b.index; + }), function (x) { + return x.value; + })); + }); + }; + async.filter = doParallel(_filter); + async.filterSeries = doSeries(_filter); + // select alias + async.select = async.filter; + async.selectSeries = async.filterSeries; + + var _reject = function (eachfn, arr, iterator, callback) { + var results = []; + arr = _map(arr, function (x, i) { + return {index: i, value: x}; + }); + eachfn(arr, function (x, callback) { + iterator(x.value, function (v) { + if (!v) { + results.push(x); + } + callback(); + }); + }, function (err) { + callback(_map(results.sort(function (a, b) { + return a.index - b.index; + }), function (x) { + return x.value; + })); + }); + }; + async.reject = doParallel(_reject); + async.rejectSeries = doSeries(_reject); + + var _detect = function (eachfn, arr, iterator, main_callback) { + eachfn(arr, function (x, callback) { + iterator(x, function (result) { + if (result) { + main_callback(x); + main_callback = function () {}; + } + else { + callback(); + } + }); + }, function (err) { + main_callback(); + }); + }; + async.detect = doParallel(_detect); + async.detectSeries = doSeries(_detect); + + async.some = function (arr, iterator, main_callback) { + async.each(arr, function (x, callback) { + iterator(x, function (v) { + if (v) { + main_callback(true); + main_callback = function () {}; + } + callback(); + }); + }, function (err) { + main_callback(false); + }); + }; + // any alias + async.any = async.some; + + async.every = function (arr, iterator, main_callback) { + async.each(arr, function (x, callback) { + iterator(x, function (v) { + if (!v) { + main_callback(false); + main_callback = function () {}; + } + callback(); + }); + }, function (err) { + main_callback(true); + }); + }; + // all alias + async.all = async.every; + + async.sortBy = function (arr, iterator, callback) { + async.map(arr, function (x, callback) { + iterator(x, function (err, criteria) { + if (err) { + callback(err); + } + else { + callback(null, {value: x, criteria: criteria}); + } + }); + }, function (err, results) { + if (err) { + return callback(err); + } + else { + var fn = function (left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }; + callback(null, _map(results.sort(fn), function (x) { + return x.value; + })); + } + }); + }; + + async.auto = function (tasks, callback) { + callback = callback || function () {}; + var keys = _keys(tasks); + var remainingTasks = keys.length + if (!remainingTasks) { + return callback(); + } + + var results = {}; + + var listeners = []; + var addListener = function (fn) { + listeners.unshift(fn); + }; + var removeListener = function (fn) { + for (var i = 0; i < listeners.length; i += 1) { + if (listeners[i] === fn) { + listeners.splice(i, 1); + return; + } + } + }; + var taskComplete = function () { + remainingTasks-- + _each(listeners.slice(0), function (fn) { + fn(); + }); + }; + + addListener(function () { + if (!remainingTasks) { + var theCallback = callback; + // prevent final callback from calling itself if it errors + callback = function () {}; + + theCallback(null, results); + } + }); + + _each(keys, function (k) { + var task = _isArray(tasks[k]) ? tasks[k]: [tasks[k]]; + var taskCallback = function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + if (err) { + var safeResults = {}; + _each(_keys(results), function(rkey) { + safeResults[rkey] = results[rkey]; + }); + safeResults[k] = args; + callback(err, safeResults); + // stop subsequent errors hitting callback multiple times + callback = function () {}; + } + else { + results[k] = args; + async.setImmediate(taskComplete); + } + }; + var requires = task.slice(0, Math.abs(task.length - 1)) || []; + var ready = function () { + return _reduce(requires, function (a, x) { + return (a && results.hasOwnProperty(x)); + }, true) && !results.hasOwnProperty(k); + }; + if (ready()) { + task[task.length - 1](taskCallback, results); + } + else { + var listener = function () { + if (ready()) { + removeListener(listener); + task[task.length - 1](taskCallback, results); + } + }; + addListener(listener); + } + }); + }; + + async.retry = function(times, task, callback) { + var DEFAULT_TIMES = 5; + var attempts = []; + // Use defaults if times not passed + if (typeof times === 'function') { + callback = task; + task = times; + times = DEFAULT_TIMES; + } + // Make sure times is a number + times = parseInt(times, 10) || DEFAULT_TIMES; + var wrappedTask = function(wrappedCallback, wrappedResults) { + var retryAttempt = function(task, finalAttempt) { + return function(seriesCallback) { + task(function(err, result){ + seriesCallback(!err || finalAttempt, {err: err, result: result}); + }, wrappedResults); + }; + }; + while (times) { + attempts.push(retryAttempt(task, !(times-=1))); + } + async.series(attempts, function(done, data){ + data = data[data.length - 1]; + (wrappedCallback || callback)(data.err, data.result); + }); + } + // If a callback is passed, run this as a controll flow + return callback ? wrappedTask() : wrappedTask + }; + + async.waterfall = function (tasks, callback) { + callback = callback || function () {}; + if (!_isArray(tasks)) { + var err = new Error('First argument to waterfall must be an array of functions'); + return callback(err); + } + if (!tasks.length) { + return callback(); + } + var wrapIterator = function (iterator) { + return function (err) { + if (err) { + callback.apply(null, arguments); + callback = function () {}; + } + else { + var args = Array.prototype.slice.call(arguments, 1); + var next = iterator.next(); + if (next) { + args.push(wrapIterator(next)); + } + else { + args.push(callback); + } + async.setImmediate(function () { + iterator.apply(null, args); + }); + } + }; + }; + wrapIterator(async.iterator(tasks))(); + }; + + var _parallel = function(eachfn, tasks, callback) { + callback = callback || function () {}; + if (_isArray(tasks)) { + eachfn.map(tasks, function (fn, callback) { + if (fn) { + fn(function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + callback.call(null, err, args); + }); + } + }, callback); + } + else { + var results = {}; + eachfn.each(_keys(tasks), function (k, callback) { + tasks[k](function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + results[k] = args; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + } + }; + + async.parallel = function (tasks, callback) { + _parallel({ map: async.map, each: async.each }, tasks, callback); + }; + + async.parallelLimit = function(tasks, limit, callback) { + _parallel({ map: _mapLimit(limit), each: _eachLimit(limit) }, tasks, callback); + }; + + async.series = function (tasks, callback) { + callback = callback || function () {}; + if (_isArray(tasks)) { + async.mapSeries(tasks, function (fn, callback) { + if (fn) { + fn(function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + callback.call(null, err, args); + }); + } + }, callback); + } + else { + var results = {}; + async.eachSeries(_keys(tasks), function (k, callback) { + tasks[k](function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (args.length <= 1) { + args = args[0]; + } + results[k] = args; + callback(err); + }); + }, function (err) { + callback(err, results); + }); + } + }; + + async.iterator = function (tasks) { + var makeCallback = function (index) { + var fn = function () { + if (tasks.length) { + tasks[index].apply(null, arguments); + } + return fn.next(); + }; + fn.next = function () { + return (index < tasks.length - 1) ? makeCallback(index + 1): null; + }; + return fn; + }; + return makeCallback(0); + }; + + async.apply = function (fn) { + var args = Array.prototype.slice.call(arguments, 1); + return function () { + return fn.apply( + null, args.concat(Array.prototype.slice.call(arguments)) + ); + }; + }; + + var _concat = function (eachfn, arr, fn, callback) { + var r = []; + eachfn(arr, function (x, cb) { + fn(x, function (err, y) { + r = r.concat(y || []); + cb(err); + }); + }, function (err) { + callback(err, r); + }); + }; + async.concat = doParallel(_concat); + async.concatSeries = doSeries(_concat); + + async.whilst = function (test, iterator, callback) { + if (test()) { + iterator(function (err) { + if (err) { + return callback(err); + } + async.whilst(test, iterator, callback); + }); + } + else { + callback(); + } + }; + + async.doWhilst = function (iterator, test, callback) { + iterator(function (err) { + if (err) { + return callback(err); + } + var args = Array.prototype.slice.call(arguments, 1); + if (test.apply(null, args)) { + async.doWhilst(iterator, test, callback); + } + else { + callback(); + } + }); + }; + + async.until = function (test, iterator, callback) { + if (!test()) { + iterator(function (err) { + if (err) { + return callback(err); + } + async.until(test, iterator, callback); + }); + } + else { + callback(); + } + }; + + async.doUntil = function (iterator, test, callback) { + iterator(function (err) { + if (err) { + return callback(err); + } + var args = Array.prototype.slice.call(arguments, 1); + if (!test.apply(null, args)) { + async.doUntil(iterator, test, callback); + } + else { + callback(); + } + }); + }; + + async.queue = function (worker, concurrency) { + if (concurrency === undefined) { + concurrency = 1; + } + function _insert(q, data, pos, callback) { + if (!q.started){ + q.started = true; + } + if (!_isArray(data)) { + data = [data]; + } + if(data.length == 0) { + // call drain immediately if there are no tasks + return async.setImmediate(function() { + if (q.drain) { + q.drain(); + } + }); + } + _each(data, function(task) { + var item = { + data: task, + callback: typeof callback === 'function' ? callback : null + }; + + if (pos) { + q.tasks.unshift(item); + } else { + q.tasks.push(item); + } + + if (q.saturated && q.tasks.length === q.concurrency) { + q.saturated(); + } + async.setImmediate(q.process); + }); + } + + var workers = 0; + var q = { + tasks: [], + concurrency: concurrency, + saturated: null, + empty: null, + drain: null, + started: false, + paused: false, + push: function (data, callback) { + _insert(q, data, false, callback); + }, + kill: function () { + q.drain = null; + q.tasks = []; + }, + unshift: function (data, callback) { + _insert(q, data, true, callback); + }, + process: function () { + if (!q.paused && workers < q.concurrency && q.tasks.length) { + var task = q.tasks.shift(); + if (q.empty && q.tasks.length === 0) { + q.empty(); + } + workers += 1; + var next = function () { + workers -= 1; + if (task.callback) { + task.callback.apply(task, arguments); + } + if (q.drain && q.tasks.length + workers === 0) { + q.drain(); + } + q.process(); + }; + var cb = only_once(next); + worker(task.data, cb); + } + }, + length: function () { + return q.tasks.length; + }, + running: function () { + return workers; + }, + idle: function() { + return q.tasks.length + workers === 0; + }, + pause: function () { + if (q.paused === true) { return; } + q.paused = true; + q.process(); + }, + resume: function () { + if (q.paused === false) { return; } + q.paused = false; + q.process(); + } + }; + return q; + }; + + async.priorityQueue = function (worker, concurrency) { + + function _compareTasks(a, b){ + return a.priority - b.priority; + }; + + function _binarySearch(sequence, item, compare) { + var beg = -1, + end = sequence.length - 1; + while (beg < end) { + var mid = beg + ((end - beg + 1) >>> 1); + if (compare(item, sequence[mid]) >= 0) { + beg = mid; + } else { + end = mid - 1; + } + } + return beg; + } + + function _insert(q, data, priority, callback) { + if (!q.started){ + q.started = true; + } + if (!_isArray(data)) { + data = [data]; + } + if(data.length == 0) { + // call drain immediately if there are no tasks + return async.setImmediate(function() { + if (q.drain) { + q.drain(); + } + }); + } + _each(data, function(task) { + var item = { + data: task, + priority: priority, + callback: typeof callback === 'function' ? callback : null + }; + + q.tasks.splice(_binarySearch(q.tasks, item, _compareTasks) + 1, 0, item); + + if (q.saturated && q.tasks.length === q.concurrency) { + q.saturated(); + } + async.setImmediate(q.process); + }); + } + + // Start with a normal queue + var q = async.queue(worker, concurrency); + + // Override push to accept second parameter representing priority + q.push = function (data, priority, callback) { + _insert(q, data, priority, callback); + }; + + // Remove unshift function + delete q.unshift; + + return q; + }; + + async.cargo = function (worker, payload) { + var working = false, + tasks = []; + + var cargo = { + tasks: tasks, + payload: payload, + saturated: null, + empty: null, + drain: null, + drained: true, + push: function (data, callback) { + if (!_isArray(data)) { + data = [data]; + } + _each(data, function(task) { + tasks.push({ + data: task, + callback: typeof callback === 'function' ? callback : null + }); + cargo.drained = false; + if (cargo.saturated && tasks.length === payload) { + cargo.saturated(); + } + }); + async.setImmediate(cargo.process); + }, + process: function process() { + if (working) return; + if (tasks.length === 0) { + if(cargo.drain && !cargo.drained) cargo.drain(); + cargo.drained = true; + return; + } + + var ts = typeof payload === 'number' + ? tasks.splice(0, payload) + : tasks.splice(0, tasks.length); + + var ds = _map(ts, function (task) { + return task.data; + }); + + if(cargo.empty) cargo.empty(); + working = true; + worker(ds, function () { + working = false; + + var args = arguments; + _each(ts, function (data) { + if (data.callback) { + data.callback.apply(null, args); + } + }); + + process(); + }); + }, + length: function () { + return tasks.length; + }, + running: function () { + return working; + } + }; + return cargo; + }; + + var _console_fn = function (name) { + return function (fn) { + var args = Array.prototype.slice.call(arguments, 1); + fn.apply(null, args.concat([function (err) { + var args = Array.prototype.slice.call(arguments, 1); + if (typeof console !== 'undefined') { + if (err) { + if (console.error) { + console.error(err); + } + } + else if (console[name]) { + _each(args, function (x) { + console[name](x); + }); + } + } + }])); + }; + }; + async.log = _console_fn('log'); + async.dir = _console_fn('dir'); + /*async.info = _console_fn('info'); + async.warn = _console_fn('warn'); + async.error = _console_fn('error');*/ + + async.memoize = function (fn, hasher) { + var memo = {}; + var queues = {}; + hasher = hasher || function (x) { + return x; + }; + var memoized = function () { + var args = Array.prototype.slice.call(arguments); + var callback = args.pop(); + var key = hasher.apply(null, args); + if (key in memo) { + async.nextTick(function () { + callback.apply(null, memo[key]); + }); + } + else if (key in queues) { + queues[key].push(callback); + } + else { + queues[key] = [callback]; + fn.apply(null, args.concat([function () { + memo[key] = arguments; + var q = queues[key]; + delete queues[key]; + for (var i = 0, l = q.length; i < l; i++) { + q[i].apply(null, arguments); + } + }])); + } + }; + memoized.memo = memo; + memoized.unmemoized = fn; + return memoized; + }; + + async.unmemoize = function (fn) { + return function () { + return (fn.unmemoized || fn).apply(null, arguments); + }; + }; + + async.times = function (count, iterator, callback) { + var counter = []; + for (var i = 0; i < count; i++) { + counter.push(i); + } + return async.map(counter, iterator, callback); + }; + + async.timesSeries = function (count, iterator, callback) { + var counter = []; + for (var i = 0; i < count; i++) { + counter.push(i); + } + return async.mapSeries(counter, iterator, callback); + }; + + async.seq = function (/* functions... */) { + var fns = arguments; + return function () { + var that = this; + var args = Array.prototype.slice.call(arguments); + var callback = args.pop(); + async.reduce(fns, args, function (newargs, fn, cb) { + fn.apply(that, newargs.concat([function () { + var err = arguments[0]; + var nextargs = Array.prototype.slice.call(arguments, 1); + cb(err, nextargs); + }])) + }, + function (err, results) { + callback.apply(that, [err].concat(results)); + }); + }; + }; + + async.compose = function (/* functions... */) { + return async.seq.apply(null, Array.prototype.reverse.call(arguments)); + }; + + var _applyEach = function (eachfn, fns /*args...*/) { + var go = function () { + var that = this; + var args = Array.prototype.slice.call(arguments); + var callback = args.pop(); + return eachfn(fns, function (fn, cb) { + fn.apply(that, args.concat([cb])); + }, + callback); + }; + if (arguments.length > 2) { + var args = Array.prototype.slice.call(arguments, 2); + return go.apply(this, args); + } + else { + return go; + } + }; + async.applyEach = doParallel(_applyEach); + async.applyEachSeries = doSeries(_applyEach); + + async.forever = function (fn, callback) { + function next(err) { + if (err) { + if (callback) { + return callback(err); + } + throw err; + } + fn(next); + } + next(); + }; + + // Node.js + if (typeof module !== 'undefined' && module.exports) { + module.exports = async; + } + // AMD / RequireJS + else if (typeof define !== 'undefined' && define.amd) { + define([], function () { + return async; + }); + } + // included directly via + + + Or, if you're using a module loader, require this module: + + // requiring the plugin will 'activate' it - no need to use + // the return value + require( 'ractive-transitions-fade' ); + + Add a fade transition like so: + +
this will fade in
+ +*/ + +(function ( global, factory ) { + + 'use strict'; + + // Common JS (i.e. browserify) environment + if ( typeof module !== 'undefined' && module.exports && typeof require === 'function' ) { + factory( require( 'ractive' ) ); + } + + // AMD? + else if ( typeof define === 'function' && define.amd ) { + define([ 'ractive' ], factory ); + } + + // browser global + else if ( global.Ractive ) { + factory( global.Ractive ); + } + + else { + throw new Error( 'Could not find Ractive! It must be loaded before the ractive-transitions-fade plugin' ); + } + +}( typeof window !== 'undefined' ? window : this, function ( Ractive ) { + + 'use strict'; + + var fade, defaults; + + defaults = { + delay: 0, + duration: 300, + easing: 'linear' + }; + + fade = function ( t, params ) { + var targetOpacity; + + params = t.processParams( params, defaults ); + + if ( t.isIntro ) { + targetOpacity = t.getStyle( 'opacity' ); + t.setStyle( 'opacity', 0 ); + } else { + targetOpacity = 0; + } + + t.animateStyle( 'opacity', targetOpacity, params ).then( t.complete ); + }; + + Ractive.transitions.fade = fade; + +})); + +},{"ractive":"/home/radek/dev/burnchart.io/node_modules/ractive/ractive.js"}],"/home/radek/dev/burnchart.io/node_modules/ractive/ractive.js":[function(require,module,exports){ +/* + ractive.js v0.6.1 + 2014-10-25 - commit 3a576eb3 + + http://ractivejs.org + http://twitter.com/RactiveJS + + Released under the MIT License. +*/ + +( function( global ) { + + 'use strict'; + + var noConflict = global.Ractive; + + /* config/defaults/options.js */ + var options = function() { + + var defaultOptions = { + // render placement: + el: void 0, + append: false, + // template: + template: { + v: 1, + t: [] + }, + yield: null, + // parse: + preserveWhitespace: false, + sanitize: false, + stripComments: true, + // data & binding: + data: {}, + computed: {}, + magic: false, + modifyArrays: true, + adapt: [], + isolated: false, + twoway: true, + lazy: false, + // transitions: + noIntro: false, + transitionsEnabled: true, + complete: void 0, + // css: + noCssTransform: false, + // debug: + debug: false + }; + return defaultOptions; + }(); + + /* config/defaults/easing.js */ + var easing = { + linear: function( pos ) { + return pos; + }, + easeIn: function( pos ) { + return Math.pow( pos, 3 ); + }, + easeOut: function( pos ) { + return Math.pow( pos - 1, 3 ) + 1; + }, + easeInOut: function( pos ) { + if ( ( pos /= 0.5 ) < 1 ) { + return 0.5 * Math.pow( pos, 3 ); + } + return 0.5 * ( Math.pow( pos - 2, 3 ) + 2 ); + } + }; + + /* circular.js */ + var circular = []; + + /* utils/hasOwnProperty.js */ + var hasOwn = Object.prototype.hasOwnProperty; + + /* utils/isArray.js */ + var isArray = function() { + + var toString = Object.prototype.toString; + // thanks, http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/ + return function( thing ) { + return toString.call( thing ) === '[object Array]'; + }; + }(); + + /* utils/isObject.js */ + var isObject = function() { + + var toString = Object.prototype.toString; + return function( thing ) { + return thing && toString.call( thing ) === '[object Object]'; + }; + }(); + + /* utils/isNumeric.js */ + var isNumeric = function( thing ) { + return !isNaN( parseFloat( thing ) ) && isFinite( thing ); + }; + + /* config/defaults/interpolators.js */ + var interpolators = function( circular, hasOwnProperty, isArray, isObject, isNumeric ) { + + var interpolators, interpolate, cssLengthPattern; + circular.push( function() { + interpolate = circular.interpolate; + } ); + cssLengthPattern = /^([+-]?[0-9]+\.?(?:[0-9]+)?)(px|em|ex|%|in|cm|mm|pt|pc)$/; + interpolators = { + number: function( from, to ) { + var delta; + if ( !isNumeric( from ) || !isNumeric( to ) ) { + return null; + } + from = +from; + to = +to; + delta = to - from; + if ( !delta ) { + return function() { + return from; + }; + } + return function( t ) { + return from + t * delta; + }; + }, + array: function( from, to ) { + var intermediate, interpolators, len, i; + if ( !isArray( from ) || !isArray( to ) ) { + return null; + } + intermediate = []; + interpolators = []; + i = len = Math.min( from.length, to.length ); + while ( i-- ) { + interpolators[ i ] = interpolate( from[ i ], to[ i ] ); + } + // surplus values - don't interpolate, but don't exclude them either + for ( i = len; i < from.length; i += 1 ) { + intermediate[ i ] = from[ i ]; + } + for ( i = len; i < to.length; i += 1 ) { + intermediate[ i ] = to[ i ]; + } + return function( t ) { + var i = len; + while ( i-- ) { + intermediate[ i ] = interpolators[ i ]( t ); + } + return intermediate; + }; + }, + object: function( from, to ) { + var properties, len, interpolators, intermediate, prop; + if ( !isObject( from ) || !isObject( to ) ) { + return null; + } + properties = []; + intermediate = {}; + interpolators = {}; + for ( prop in from ) { + if ( hasOwnProperty.call( from, prop ) ) { + if ( hasOwnProperty.call( to, prop ) ) { + properties.push( prop ); + interpolators[ prop ] = interpolate( from[ prop ], to[ prop ] ); + } else { + intermediate[ prop ] = from[ prop ]; + } + } + } + for ( prop in to ) { + if ( hasOwnProperty.call( to, prop ) && !hasOwnProperty.call( from, prop ) ) { + intermediate[ prop ] = to[ prop ]; + } + } + len = properties.length; + return function( t ) { + var i = len, + prop; + while ( i-- ) { + prop = properties[ i ]; + intermediate[ prop ] = interpolators[ prop ]( t ); + } + return intermediate; + }; + } + }; + return interpolators; + }( circular, hasOwn, isArray, isObject, isNumeric ); + + /* config/svg.js */ + var svg = function() { + + var svg; + if ( typeof document === 'undefined' ) { + svg = false; + } else { + svg = document && document.implementation.hasFeature( 'http://www.w3.org/TR/SVG11/feature#BasicStructure', '1.1' ); + } + return svg; + }(); + + /* utils/warn.js */ + var warn = function() { + + /* global console */ + var warn, warned = {}; + if ( typeof console !== 'undefined' && typeof console.warn === 'function' && typeof console.warn.apply === 'function' ) { + warn = function( message, allowDuplicates ) { + if ( !allowDuplicates ) { + if ( warned[ message ] ) { + return; + } + warned[ message ] = true; + } + console.warn( '%cRactive.js: %c' + message, 'color: rgb(114, 157, 52);', 'color: rgb(85, 85, 85);' ); + }; + } else { + warn = function() {}; + } + return warn; + }(); + + /* config/errors.js */ + var errors = { + missingParser: 'Missing Ractive.parse - cannot parse template. Either preparse or use the version that includes the parser', + mergeComparisonFail: 'Merge operation: comparison failed. Falling back to identity checking', + noComponentEventArguments: 'Components currently only support simple events - you cannot include arguments. Sorry!', + noTemplateForPartial: 'Could not find template for partial "{name}"', + noNestedPartials: 'Partials ({{>{name}}}) cannot contain nested inline partials', + evaluationError: 'Error evaluating "{uniqueString}": {err}', + badArguments: 'Bad arguments "{arguments}". I\'m not allowed to argue unless you\'ve paid.', + failedComputation: 'Failed to compute "{key}": {err}', + missingPlugin: 'Missing "{name}" {plugin} plugin. You may need to download a {plugin} via http://docs.ractivejs.org/latest/plugins#{plugin}s', + badRadioInputBinding: 'A radio input can have two-way binding on its name attribute, or its checked attribute - not both', + noRegistryFunctionReturn: 'A function was specified for "{name}" {registry}, but no {registry} was returned', + defaultElSpecified: 'The <{name}/> component has a default `el` property; it has been disregarded', + noElementProxyEventWildcards: 'Only component proxy-events may contain "*" wildcards, <{element} on-{event}/> is not valid.', + methodDeprecated: 'The method "{deprecated}" has been deprecated in favor of "{replacement}" and will likely be removed in a future release. See http://docs.ractivejs.org/latest/migrating for more information.' + }; + + /* utils/log.js */ + var log = function( consolewarn, errors ) { + + var log = { + warn: function( options, passthru ) { + if ( !options.debug && !passthru ) { + return; + } + this.warnAlways( options ); + }, + warnAlways: function( options ) { + this.logger( getMessage( options ), options.allowDuplicates ); + }, + error: function( options ) { + this.errorOnly( options ); + if ( !options.debug ) { + this.warn( options, true ); + } + }, + errorOnly: function( options ) { + if ( options.debug ) { + this.critical( options ); + } + }, + critical: function( options ) { + var err = options.err || new Error( getMessage( options ) ); + this.thrower( err ); + }, + logger: consolewarn, + thrower: function( err ) { + throw err; + } + }; + + function getMessage( options ) { + var message = errors[ options.message ] || options.message || ''; + return interpolate( message, options.args ); + } + // simple interpolation. probably quicker (and better) out there, + // but log is not in golden path of execution, only exceptions + function interpolate( message, args ) { + return message.replace( /{([^{}]*)}/g, function( a, b ) { + return args[ b ]; + } ); + } + return log; + }( warn, errors ); + + /* Ractive/prototype/shared/hooks/Hook.js */ + var Ractive$shared_hooks_Hook = function( log ) { + + var deprecations = { + construct: { + deprecated: 'beforeInit', + replacement: 'onconstruct' + }, + render: { + deprecated: 'init', + message: 'The "init" method has been deprecated ' + 'and will likely be removed in a future release. ' + 'You can either use the "oninit" method which will fire ' + 'only once prior to, and regardless of, any eventual ractive ' + 'instance being rendered, or if you need to access the ' + 'rendered DOM, use "onrender" instead. ' + 'See http://docs.ractivejs.org/latest/migrating for more information.' + }, + complete: { + deprecated: 'complete', + replacement: 'oncomplete' + } + }; + + function Hook( event ) { + this.event = event; + this.method = 'on' + event; + this.deprecate = deprecations[ event ]; + } + Hook.prototype.fire = function( ractive, arg ) { + function call( method ) { + if ( ractive[ method ] ) { + arg ? ractive[ method ]( arg ) : ractive[ method ](); + return true; + } + } + call( this.method ); + if ( !ractive[ this.method ] && this.deprecate && call( this.deprecate.deprecated ) ) { + log.warnAlways( { + debug: ractive.debug, + message: this.deprecate.message || 'methodDeprecated', + args: this.deprecate + } ); + } + arg ? ractive.fire( this.event, arg ) : ractive.fire( this.event ); + }; + return Hook; + }( log ); + + /* utils/removeFromArray.js */ + var removeFromArray = function( array, member ) { + var index = array.indexOf( member ); + if ( index !== -1 ) { + array.splice( index, 1 ); + } + }; + + /* utils/Promise.js */ + var Promise = function() { + + var __export; + var _Promise, PENDING = {}, + FULFILLED = {}, + REJECTED = {}; + if ( typeof Promise === 'function' ) { + // use native Promise + _Promise = Promise; + } else { + _Promise = function( callback ) { + var fulfilledHandlers = [], + rejectedHandlers = [], + state = PENDING, + result, dispatchHandlers, makeResolver, fulfil, reject, promise; + makeResolver = function( newState ) { + return function( value ) { + if ( state !== PENDING ) { + return; + } + result = value; + state = newState; + dispatchHandlers = makeDispatcher( state === FULFILLED ? fulfilledHandlers : rejectedHandlers, result ); + // dispatch onFulfilled and onRejected handlers asynchronously + wait( dispatchHandlers ); + }; + }; + fulfil = makeResolver( FULFILLED ); + reject = makeResolver( REJECTED ); + try { + callback( fulfil, reject ); + } catch ( err ) { + reject( err ); + } + promise = { + // `then()` returns a Promise - 2.2.7 + then: function( onFulfilled, onRejected ) { + var promise2 = new _Promise( function( fulfil, reject ) { + var processResolutionHandler = function( handler, handlers, forward ) { + // 2.2.1.1 + if ( typeof handler === 'function' ) { + handlers.push( function( p1result ) { + var x; + try { + x = handler( p1result ); + resolve( promise2, x, fulfil, reject ); + } catch ( err ) { + reject( err ); + } + } ); + } else { + // Forward the result of promise1 to promise2, if resolution handlers + // are not given + handlers.push( forward ); + } + }; + // 2.2 + processResolutionHandler( onFulfilled, fulfilledHandlers, fulfil ); + processResolutionHandler( onRejected, rejectedHandlers, reject ); + if ( state !== PENDING ) { + // If the promise has resolved already, dispatch the appropriate handlers asynchronously + wait( dispatchHandlers ); + } + } ); + return promise2; + } + }; + promise[ 'catch' ] = function( onRejected ) { + return this.then( null, onRejected ); + }; + return promise; + }; + _Promise.all = function( promises ) { + return new _Promise( function( fulfil, reject ) { + var result = [], + pending, i, processPromise; + if ( !promises.length ) { + fulfil( result ); + return; + } + processPromise = function( i ) { + promises[ i ].then( function( value ) { + result[ i ] = value; + if ( !--pending ) { + fulfil( result ); + } + }, reject ); + }; + pending = i = promises.length; + while ( i-- ) { + processPromise( i ); + } + } ); + }; + _Promise.resolve = function( value ) { + return new _Promise( function( fulfil ) { + fulfil( value ); + } ); + }; + _Promise.reject = function( reason ) { + return new _Promise( function( fulfil, reject ) { + reject( reason ); + } ); + }; + } + __export = _Promise; + // TODO use MutationObservers or something to simulate setImmediate + function wait( callback ) { + setTimeout( callback, 0 ); + } + + function makeDispatcher( handlers, result ) { + return function() { + var handler; + while ( handler = handlers.shift() ) { + handler( result ); + } + }; + } + + function resolve( promise, x, fulfil, reject ) { + // Promise Resolution Procedure + var then; + // 2.3.1 + if ( x === promise ) { + throw new TypeError( 'A promise\'s fulfillment handler cannot return the same promise' ); + } + // 2.3.2 + if ( x instanceof _Promise ) { + x.then( fulfil, reject ); + } else if ( x && ( typeof x === 'object' || typeof x === 'function' ) ) { + try { + then = x.then; + } catch ( e ) { + reject( e ); + // 2.3.3.2 + return; + } + // 2.3.3.3 + if ( typeof then === 'function' ) { + var called, resolvePromise, rejectPromise; + resolvePromise = function( y ) { + if ( called ) { + return; + } + called = true; + resolve( promise, y, fulfil, reject ); + }; + rejectPromise = function( r ) { + if ( called ) { + return; + } + called = true; + reject( r ); + }; + try { + then.call( x, resolvePromise, rejectPromise ); + } catch ( e ) { + if ( !called ) { + // 2.3.3.3.4.1 + reject( e ); + // 2.3.3.3.4.2 + called = true; + return; + } + } + } else { + fulfil( x ); + } + } else { + fulfil( x ); + } + } + return __export; + }(); + + /* utils/normaliseRef.js */ + var normaliseRef = function() { + + var regex = /\[\s*(\*|[0-9]|[1-9][0-9]+)\s*\]/g; + return function normaliseRef( ref ) { + return ( ref || '' ).replace( regex, '.$1' ); + }; + }(); + + /* shared/getInnerContext.js */ + var getInnerContext = function( fragment ) { + do { + if ( fragment.context !== undefined ) { + return fragment.context; + } + } while ( fragment = fragment.parent ); + return ''; + }; + + /* utils/isEqual.js */ + var isEqual = function( a, b ) { + if ( a === null && b === null ) { + return true; + } + if ( typeof a === 'object' || typeof b === 'object' ) { + return false; + } + return a === b; + }; + + /* shared/createComponentBinding.js */ + var createComponentBinding = function( circular, isEqual ) { + + var runloop; + circular.push( function() { + return runloop = circular.runloop; + } ); + var Binding = function( ractive, keypath, otherInstance, otherKeypath ) { + var this$0 = this; + this.root = ractive; + this.keypath = keypath; + this.otherInstance = otherInstance; + this.otherKeypath = otherKeypath; + this.lock = function() { + return this$0.updating = true; + }; + this.unlock = function() { + return this$0.updating = false; + }; + this.bind(); + this.value = this.root.viewmodel.get( this.keypath ); + }; + Binding.prototype = { + isLocked: function() { + return this.updating || this.counterpart && this.counterpart.updating; + }, + shuffle: function( newIndices, value ) { + this.propagateChange( value, newIndices ); + }, + setValue: function( value ) { + this.propagateChange( value ); + }, + propagateChange: function( value, newIndices ) { + var other; + // Only *you* can prevent infinite loops + if ( this.isLocked() ) { + this.value = value; + return; + } + if ( !isEqual( value, this.value ) ) { + this.lock(); + // TODO maybe the case that `value === this.value` - should that result + // in an update rather than a set? + // if the other viewmodel is already locked up, need to do a deferred update + if ( !runloop.addViewmodel( other = this.otherInstance.viewmodel ) && this.counterpart.value !== value ) { + runloop.scheduleTask( function() { + return runloop.addViewmodel( other ); + } ); + } + if ( newIndices ) { + other.smartUpdate( this.otherKeypath, value, newIndices ); + } else { + if ( isSettable( other, this.otherKeypath ) ) { + other.set( this.otherKeypath, value ); + } + } + this.value = value; + // TODO will the counterpart update after this line, during + // the runloop end cycle? may be a problem... + runloop.scheduleTask( this.unlock ); + } + }, + refineValue: function( keypaths ) { + var this$0 = this; + var other; + if ( this.isLocked() ) { + return; + } + this.lock(); + runloop.addViewmodel( other = this.otherInstance.viewmodel ); + keypaths.map( function( keypath ) { + return this$0.otherKeypath + keypath.substr( this$0.keypath.length ); + } ).forEach( function( keypath ) { + return other.mark( keypath ); + } ); + runloop.scheduleTask( this.unlock ); + }, + bind: function() { + this.root.viewmodel.register( this.keypath, this ); + }, + rebind: function( newKeypath ) { + this.unbind(); + this.keypath = newKeypath; + this.counterpart.otherKeypath = newKeypath; + this.bind(); + }, + unbind: function() { + this.root.viewmodel.unregister( this.keypath, this ); + } + }; + + function isSettable( viewmodel, keypath ) { + var computed = viewmodel.computations[ keypath ]; + return !computed || computed.setter; + } + return function createComponentBinding( component, parentInstance, parentKeypath, childKeypath ) { + var hash, childInstance, bindings, parentToChildBinding, childToParentBinding; + hash = parentKeypath + '=' + childKeypath; + bindings = component.bindings; + if ( bindings[ hash ] ) { + // TODO does this ever happen? + return; + } + childInstance = component.instance; + parentToChildBinding = new Binding( parentInstance, parentKeypath, childInstance, childKeypath ); + bindings.push( parentToChildBinding ); + if ( childInstance.twoway ) { + childToParentBinding = new Binding( childInstance, childKeypath, parentInstance, parentKeypath ); + bindings.push( childToParentBinding ); + parentToChildBinding.counterpart = childToParentBinding; + childToParentBinding.counterpart = parentToChildBinding; + } + bindings[ hash ] = parentToChildBinding; + }; + }( circular, isEqual ); + + /* shared/resolveRef.js */ + var resolveRef = function( normaliseRef, getInnerContext, createComponentBinding ) { + + var __export; + var ancestorErrorMessage, getOptions; + ancestorErrorMessage = 'Could not resolve reference - too many "../" prefixes'; + getOptions = { + evaluateWrapped: true + }; + __export = function resolveRef( ractive, ref, fragment, isParentLookup ) { + var context, key, index, keypath, parentValue, hasContextChain, parentKeys, childKeys, parentKeypath, childKeypath; + ref = normaliseRef( ref ); + // If a reference begins '~/', it's a top-level reference + if ( ref.substr( 0, 2 ) === '~/' ) { + return ref.substring( 2 ); + } + // If a reference begins with '.', it's either a restricted reference or + // an ancestor reference... + if ( ref.charAt( 0 ) === '.' ) { + return resolveAncestorReference( getInnerContext( fragment ), ref ); + } + // ...otherwise we need to find the keypath + key = ref.split( '.' )[ 0 ]; + // get() in viewmodel creation means no fragment (yet) + fragment = fragment || {}; + do { + context = fragment.context; + if ( !context ) { + continue; + } + hasContextChain = true; + parentValue = ractive.viewmodel.get( context, getOptions ); + if ( parentValue && ( typeof parentValue === 'object' || typeof parentValue === 'function' ) && key in parentValue ) { + return context + '.' + ref; + } + } while ( fragment = fragment.parent ); + // Root/computed property? + if ( key in ractive.data || key in ractive.viewmodel.computations ) { + return ref; + } + // If this is an inline component, and it's not isolated, we + // can try going up the scope chain + if ( ractive._parent && !ractive.isolated ) { + hasContextChain = true; + fragment = ractive.component.parentFragment; + // Special case - index refs + if ( fragment.indexRefs && ( index = fragment.indexRefs[ ref ] ) !== undefined ) { + // Create an index ref binding, so that it can be rebound letter if necessary. + // It doesn't have an alias since it's an implicit binding, hence `...[ ref ] = ref` + ractive.component.indexRefBindings[ ref ] = ref; + ractive.viewmodel.set( ref, index, true ); + return; + } + keypath = resolveRef( ractive._parent, ref, fragment, true ); + if ( keypath ) { + // We need to create an inter-component binding + // If parent keypath is 'one.foo' and child is 'two.foo', we bind + // 'one' to 'two' as it's more efficient and avoids edge cases + parentKeys = keypath.split( '.' ); + childKeys = ref.split( '.' ); + while ( parentKeys.length > 1 && childKeys.length > 1 && parentKeys[ parentKeys.length - 1 ] === childKeys[ childKeys.length - 1 ] ) { + parentKeys.pop(); + childKeys.pop(); + } + parentKeypath = parentKeys.join( '.' ); + childKeypath = childKeys.join( '.' ); + ractive.viewmodel.set( childKeypath, ractive._parent.viewmodel.get( parentKeypath ), true ); + createComponentBinding( ractive.component, ractive._parent, parentKeypath, childKeypath ); + return ref; + } + } + // If there's no context chain, and the instance is either a) isolated or + // b) an orphan, then we know that the keypath is identical to the reference + if ( !isParentLookup && !hasContextChain ) { + // the data object needs to have a property by this name, + // to prevent future failed lookups + ractive.viewmodel.set( ref, undefined ); + return ref; + } + if ( ractive.viewmodel.get( ref ) !== undefined ) { + return ref; + } + }; + + function resolveAncestorReference( baseContext, ref ) { + var contextKeys; + // {{.}} means 'current context' + if ( ref === '.' ) + return baseContext; + contextKeys = baseContext ? baseContext.split( '.' ) : []; + // ancestor references (starting "../") go up the tree + if ( ref.substr( 0, 3 ) === '../' ) { + while ( ref.substr( 0, 3 ) === '../' ) { + if ( !contextKeys.length ) { + throw new Error( ancestorErrorMessage ); + } + contextKeys.pop(); + ref = ref.substring( 3 ); + } + contextKeys.push( ref ); + return contextKeys.join( '.' ); + } + // not an ancestor reference - must be a restricted reference (prepended with "." or "./") + if ( !baseContext ) { + return ref.replace( /^\.\/?/, '' ); + } + return baseContext + ref.replace( /^\.\//, '.' ); + } + return __export; + }( normaliseRef, getInnerContext, createComponentBinding ); + + /* global/TransitionManager.js */ + var TransitionManager = function( removeFromArray ) { + + var TransitionManager = function( callback, parent ) { + this.callback = callback; + this.parent = parent; + this.intros = []; + this.outros = []; + this.children = []; + this.totalChildren = this.outroChildren = 0; + this.detachQueue = []; + this.outrosComplete = false; + if ( parent ) { + parent.addChild( this ); + } + }; + TransitionManager.prototype = { + addChild: function( child ) { + this.children.push( child ); + this.totalChildren += 1; + this.outroChildren += 1; + }, + decrementOutros: function() { + this.outroChildren -= 1; + check( this ); + }, + decrementTotal: function() { + this.totalChildren -= 1; + check( this ); + }, + add: function( transition ) { + var list = transition.isIntro ? this.intros : this.outros; + list.push( transition ); + }, + remove: function( transition ) { + var list = transition.isIntro ? this.intros : this.outros; + removeFromArray( list, transition ); + check( this ); + }, + init: function() { + this.ready = true; + check( this ); + }, + detachNodes: function() { + this.detachQueue.forEach( detach ); + this.children.forEach( detachNodes ); + } + }; + + function detach( element ) { + element.detach(); + } + + function detachNodes( tm ) { + tm.detachNodes(); + } + + function check( tm ) { + if ( !tm.ready || tm.outros.length || tm.outroChildren ) + return; + // If all outros are complete, and we haven't already done this, + // we notify the parent if there is one, otherwise + // start detaching nodes + if ( !tm.outrosComplete ) { + if ( tm.parent ) { + tm.parent.decrementOutros( tm ); + } else { + tm.detachNodes(); + } + tm.outrosComplete = true; + } + // Once everything is done, we can notify parent transition + // manager and call the callback + if ( !tm.intros.length && !tm.totalChildren ) { + if ( typeof tm.callback === 'function' ) { + tm.callback(); + } + if ( tm.parent ) { + tm.parent.decrementTotal(); + } + } + } + return TransitionManager; + }( removeFromArray ); + + /* global/runloop.js */ + var runloop = function( circular, Hook, removeFromArray, Promise, resolveRef, TransitionManager ) { + + var __export; + var batch, runloop, unresolved = [], + changeHook = new Hook( 'change' ); + runloop = { + start: function( instance, returnPromise ) { + var promise, fulfilPromise; + if ( returnPromise ) { + promise = new Promise( function( f ) { + return fulfilPromise = f; + } ); + } + batch = { + previousBatch: batch, + transitionManager: new TransitionManager( fulfilPromise, batch && batch.transitionManager ), + views: [], + tasks: [], + viewmodels: [], + instance: instance + }; + if ( instance ) { + batch.viewmodels.push( instance.viewmodel ); + } + return promise; + }, + end: function() { + flushChanges(); + batch.transitionManager.init(); + if ( !batch.previousBatch && !!batch.instance ) + batch.instance.viewmodel.changes = []; + batch = batch.previousBatch; + }, + addViewmodel: function( viewmodel ) { + if ( batch ) { + if ( batch.viewmodels.indexOf( viewmodel ) === -1 ) { + batch.viewmodels.push( viewmodel ); + return true; + } else { + return false; + } + } else { + viewmodel.applyChanges(); + return false; + } + }, + registerTransition: function( transition ) { + transition._manager = batch.transitionManager; + batch.transitionManager.add( transition ); + }, + addView: function( view ) { + batch.views.push( view ); + }, + addUnresolved: function( thing ) { + unresolved.push( thing ); + }, + removeUnresolved: function( thing ) { + removeFromArray( unresolved, thing ); + }, + // synchronise node detachments with transition ends + detachWhenReady: function( thing ) { + batch.transitionManager.detachQueue.push( thing ); + }, + scheduleTask: function( task, postRender ) { + var _batch; + if ( !batch ) { + task(); + } else { + _batch = batch; + while ( postRender && _batch.previousBatch ) { + // this can't happen until the DOM has been fully updated + // otherwise in some situations (with components inside elements) + // transitions and decorators will initialise prematurely + _batch = _batch.previousBatch; + } + _batch.tasks.push( task ); + } + } + }; + circular.runloop = runloop; + __export = runloop; + + function flushChanges() { + var i, thing, changeHash; + for ( i = 0; i < batch.viewmodels.length; i += 1 ) { + thing = batch.viewmodels[ i ]; + changeHash = thing.applyChanges(); + if ( changeHash ) { + changeHook.fire( thing.ractive, changeHash ); + } + } + batch.viewmodels.length = 0; + attemptKeypathResolution(); + // Now that changes have been fully propagated, we can update the DOM + // and complete other tasks + for ( i = 0; i < batch.views.length; i += 1 ) { + batch.views[ i ].update(); + } + batch.views.length = 0; + for ( i = 0; i < batch.tasks.length; i += 1 ) { + batch.tasks[ i ](); + } + batch.tasks.length = 0; + // If updating the view caused some model blowback - e.g. a triple + // containing